void main(int argc, char** argv) { if(geteuid() != 0) { fprintf(stderr, "You need root permissions\n"); exit(1); } //TODO : Add a debug mode char* interface; if(argc > 1) interface = argv[1]; else { fprintf(stderr, "Please specify network interface to use\n"); exit(1); } // printf("Interface = %s\n", interface); int sock = socket(PF_PACKET, SOCK_DGRAM, htons(ETH_P_IP)); //Set receive timeout struct timeval tv; tv.tv_usec = 0; tv.tv_sec = 10; //10 seconds in case of latency on the network setsockopt(sock, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv)); //retrieve ethernet NIC index and HW address struct hw_eth_iface iface = find_iface(sock, interface); // TODO : Check interface existency, and print a list of possible NIC struct sockaddr_ll target; memset(&target, 0, sizeof(target)); target.sll_family = PF_PACKET; target.sll_protocol = htons(ETH_P_IP); target.sll_ifindex = iface.index; target.sll_hatype = ARPHRD_ETHER; target.sll_pkttype = PACKET_HOST; target.sll_halen = ETH_ALEN; memset(target.sll_addr, 0xff, 6); char buffer[BUFF_SIZE]; // struct dhcp_pkt *dhcp = (struct dhcp_pkt*)(buffer + sizeof(struct udpheader) + sizeof(struct ipheader)); struct dhcp_pkt dhcp; int dhcp_len = build_dhcp_discover(&dhcp, iface.hw_addr, iface.addr_len); int len = build_ip4_udp_pkt(buffer, BUFF_SIZE, (unsigned char*)&dhcp, dhcp_len, "0.0.0.0", "255.255.255.255", 68, 67, IPPROTO_UDP); //Send the packet over the network if(sendto(sock, buffer, len, 0, (struct sockaddr *)&target, sizeof(target)) < 0) { perror("Error while writing to socket"); exit(1); } //Now, wait for the server response, and read it receive: memset(buffer, 0, BUFF_SIZE); //Read a packet int read_len = recvfrom(sock, buffer, BUFF_SIZE, 0, NULL, NULL); if(read_len <= 0) { perror("Cannot read"); exit(1); } struct ipheader *rip = (struct ipheader*) buffer; struct udpheader *rudp = (struct udpheader*)(buffer + sizeof(struct ipheader)); struct dhcp_pkt *rdhcp = (struct dhcp_pkt*)(buffer + sizeof(struct udpheader) + sizeof(struct ipheader)); //Check packet validity // if dest port isn't our or packet is not a dhcp one, drop the packet if(rip->iph_protocol != IPPROTO_UDP || rudp->udph_destport != htons(68) || !is_dhcp(rdhcp) || rdhcp->op != OP_BOOT_REPLY) goto receive; // printf("Data Recieved, length = %d\n", read_len); //Find the IP attributed to us by the server struct in_addr raddr; raddr.s_addr = rdhcp->yi_addr; printf("IPADDR=%s\n", inet_ntoa(raddr)); //Now check DHCP options, and process them struct dhcp_opt *opt = NULL; int offs = 0; opt = get_dhcp_option(rdhcp, &offs); while(opt != NULL) { // printf("OPT FOUND offset = %d\n", offs); switch(opt->id) { case OPTION_ROUTER: // If the option is the gateway address if(opt->len == 4) { raddr.s_addr = char_to_ip(opt->values); printf("GATEWAY=%s\n", inet_ntoa(raddr)); } break; case OPTION_SUBNET_MASK: // If the option is the netwmask if(opt->len == 4) { raddr.s_addr = char_to_ip(opt->values); printf("NETMASK=%s\n", inet_ntoa(raddr)); } break; case OPTION_DNS: // If option is the DNS addresses if(opt->len % 4 == 0) { int i = 0; printf("NAMESERVER="); int max = opt->len / 4; for(i = 0; i < max; i++) { raddr.s_addr = char_to_ip(opt->values + 4*i); printf("%s", inet_ntoa(raddr)); if(i < max - 1) printf(","); } printf("\n"); } break; default: break; } opt = get_dhcp_option(rdhcp, &offs); } close(sock); exit(0); }
void dhcp_reply(struct dhcp_packet *p, struct sockaddr* client_address, socklen_t client_addrlen) { int packet_len; u_char *opt; u_char optlen; struct dhcp_packet re; int res; DBG("dhcp_reply start"); if (check_dhcp_packet(p) == -1) { DBG("got a invalid dhcp packet"); return; } if (get_dhcp_message_type(p) == DHCPDISCOVER) { DBG("got a DHCPDISCOVER on dhcp"); } else { DBG("got a non-DHCPDISCOVER dhcp packet"); return; } /* check vendor class identifier ("PXEClient") */ res = get_dhcp_option(p, DHO_VENDOR_CLASS_IDENTIFIER, &opt, &optlen); if (res == -1 || strncmp((char*)opt, PXE_IDENTIFIER_STRING, strlen(PXE_IDENTIFIER_STRING)) != 0) { LOG("got a non-PXE dhcp packet"); return; } /* create response */ init_packet(&re, p, DHCPOFFER); /* re.ciaddr is 0.0.0.0 */ /* re.yiaddr is 0.0.0.0 */ re.siaddr = tftp_ip; memcpy(re.chaddr, p->chaddr, sizeof(re.chaddr)); strcpy(re.file, nbp_name); /* set vendor class identifier */ res = add_dhcp_option(&re, DHO_VENDOR_CLASS_IDENTIFIER, (u_char*)PXE_IDENTIFIER_STRING, strlen(PXE_IDENTIFIER_STRING)+1); if (res == -1) { DBG("add_dhcp_option() failed"); return; } /* set vendor options */ { u_char vop[3]; vop[0] = PXE_DISCOVERY_CONTROL; vop[1] = 1; vop[2] = PXE_DISCOVERY_CONTROL_BIT3; if (add_dhcp_option(&re, DHO_VENDOR_ENCAPSULATED_OPTIONS, vop, 3) == -1) { DBG("add_dhcp_option() failed"); return; } } /* send the response */ packet_len = get_dhcp_packet_len(&re); res = sendto(server_socket, &re, packet_len, 0, (struct sockaddr*)&bcast_address, sizeof(bcast_address)); if (res != packet_len) { LOG("sendto() failed or was not complete: %s", strerror(errno)); return; } DBG("dhcp_reply end"); }
/* * parses the request and send the spoofed reply */ static void dhcp_spoofing_req(struct packet_object *po) { char dhcp_hdr[LIBNET_DHCPV4_H]; struct libnet_dhcpv4_hdr *dhcp; u_int8 *options, *opt, *end; struct ip_addr client, server; char tmp[MAX_ASCII_ADDR_LEN]; DEBUG_MSG("dhcp_spoofing_req"); /* get a local copy of the dhcp header */ memcpy(dhcp_hdr, po->DATA.data, LIBNET_DHCPV4_H); dhcp = (struct libnet_dhcpv4_hdr *)dhcp_hdr; /* get the pointers to options */ options = po->DATA.data + LIBNET_DHCPV4_H; end = po->DATA.data + po->DATA.len; /* use the same dhcp header, but change the type of the message */ dhcp->dhcp_opcode = LIBNET_DHCP_REPLY; /* * if the client is requesting a particular IP address, * release it. so we don't mess the network too much... * only change the router ip ;) */ /* get the requested ip */ if ((opt = get_dhcp_option(DHCP_OPT_RQ_ADDR, options, end)) != NULL) ip_addr_init(&client, AF_INET, opt + 1); else { /* search if the client already has the ip address */ if (dhcp->dhcp_cip != 0) { ip_addr_init(&client, AF_INET, (u_char *)&dhcp->dhcp_cip); } else return; } /* set the requested ip */ dhcp->dhcp_yip = ip_addr_to_int32(&client.addr); /* this is a dhcp ACK */ dhcp_options[2] = DHCP_ACK; /* * if it is a request after an offer from a server, * spoof its ip to be stealth. */ if ((opt = get_dhcp_option(DHCP_OPT_SRV_ADDR, options, end)) != NULL) { /* get the server id */ ip_addr_init(&server, AF_INET, opt + 1); /* set it in the header */ dhcp->dhcp_sip = ip_addr_to_int32(&server.addr); /* set it in the options */ ip_addr_cpy((u_char*)dhcp_options + 5, &server); send_dhcp_reply(&server, dhcp_addr_reply(&po->L3.src), po->L2.src, (u_char*)dhcp_hdr, (u_char*)dhcp_options, dhcp_optlen); } else { /* * the request does not contain an identifier, * use our ip address */ dhcp->dhcp_sip = ip_addr_to_int32(&GBL_IFACE->ip.addr); /* set it in the options */ ip_addr_cpy((u_char*)dhcp_options + 5, &GBL_IFACE->ip); send_dhcp_reply(&GBL_IFACE->ip, dhcp_addr_reply(&po->L3.src), po->L2.src, (u_char*)dhcp_hdr, (u_char*)dhcp_options, dhcp_optlen); } USER_MSG("DHCP spoofing: fake ACK [%s] ", mac_addr_ntoa(po->L2.src, tmp)); USER_MSG("assigned to %s \n", ip_addr_ntoa(&client, tmp)); }