Jump to content
 Share

Roy

[C] UDP Spoof Program

Recommended Posts

Hey everyone,

 

I just wanted to share my UDP Spoofing program I made earlier to test if I was able to send spoofed UDP packets to a host. This program uses raw sockets and manually sets the IP + UDP headers for spoofing purposes. It also includes being able to set a timeout for received packets and the payload data itself as a string.

 

Note - Receiving successful replies are probably a bit buggy in this application due to the recvfrom() function call being in non-blocking mode. I didn't design this program to receive replies properly, but that's fine because its main purpose is to send out packets. I will probably be making another program that uses epoll() and will receive packet replies properly next time.

 

Note - The UDP Header's Checksum is not calculated in this program. I figured it wasn't really needed for the general use case, but I will be calculating it in future programs I make.

 

Usage

./UDP_Spoof <Source IP> <Source Port> <Destination IP> <Destination Port> [<Time out> <Data>]

 

Usage Example

./UDP_Spoof 10.50.0.3 12345 10.50.0.4 12345 1 "HELLO!"

 

Server Example For Testing Purposes

#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>

#define PCKT_LEN 8192

extern int errno;

volatile sig_atomic_t cont = 1;

void signHdl(int tmp)
{
    cont = 0;
}

int main(int argc, char *argv[])
{
    if (argc < 3)
    {
        fprintf(stdout, "Usage: %s <Bind IP> <Bind Port>", argv[0]);

        exit(0);
    }

    // Initialize variables.
    char buffer[PCKT_LEN];
    int sockfd;
    struct sockaddr_in sin;
    struct sockaddr_in din;
    int one = 1;

    struct timeval tv;
    tv.tv_sec = 3;
    tv.tv_usec = 0;

    int dinSize = sizeof(din);
    int data = 0;

    // Fill out source sockaddr_in.
    sin.sin_family = AF_INET;
    sin.sin_port = htons(atoi(argv[2]));
    sin.sin_addr.s_addr = inet_addr(argv[1]);

    // Create socket.
    sockfd = socket(PF_INET, SOCK_DGRAM, 0);

    // Check for any errors with socket creation.
    if (sockfd <= 0)
    {
        fprintf(stderr, "Socket error - %s\n", strerror(errno));
        perror("socket");

        exit(1);
    }

    // Bind socket and check for errors.
    if (bind(sockfd, (struct sockaddr *)&sin, sizeof(sin)) < 0)
    {
        fprintf(stderr, "Socket Bind error - %s\n", strerror(errno));
        perror("bind");

        exit(1);
    }

    // Set reuse option.
    if (setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(one)) < 0)
    {
        fprintf(stderr, "Socket option error (reuse) - %s\n", strerror(errno));
        perror("setsockopt");

        exit(1);
    }

    // Set timeout.
    if (setsockopt(sockfd, SOL_SOCKET, SO_RCVTIMEO, (const char *)&tv, sizeof(tv)) < 0)
    {
        fprintf(stderr, "Socket option error (timeout) - %s\n", strerror(errno));
        perror("setsockopt");

        exit(1);   
    }

    // Set signal handle.
    signal(SIGINT, signHdl);

    // Let client know details.
    fprintf(stdout, "Program bound to %s:%u. Waiting for packets...\n", argv[1], atoi(argv[2]));
    
    // Loop.
    while (cont)
    {
        data = recvfrom(sockfd, buffer, PCKT_LEN, 0, (struct sockaddr *)&din, &dinSize);

        // Check data amount.
        if (data < 0)
        {
            continue;
        }

        fprintf(stdout, "Got a packet with size of %d\n", data);
        // Let's send data back.
        if (sendto(sockfd, buffer, data, 0, (struct sockaddr *)&sin, sizeof(sin)) <= 0)
        {
            fprintf(stderr, "Error sending packet back.\n");
        }
    }

    // Close socket.
    close(sockfd);

    // Close program.
    exit(0);
}

 

Note - This is also very buggy due to non-blocking mode. You can remove the setsockopt code for setting a timeout which will result being put back into blocking mode (this will prevent the program from sending out many packets due to the while loop). The only issue is the signal function doesn't work and you'll have to forcefully kill the process in Linux (I usually get the process id by doing ps -aux | grep "<App Name>" and use the kill <pid> command). I just made the above to simply test if I'm receiving data properly on the server. In the future, I'll be making UDP servers that need to receive packets using epoll() along with pthreads

 

Gitlab Project (Download)

 

Thanks!

Share this post


Link to post
Share on other sites


Here's the program's source code as of 2-22-20 (for anyone that can't find the source code on GitLab for w/e reason). I'm not sure if I'll make edits to it in the future. I'll probably end up making a new program entirely.

 

#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>

#define PCKT_LEN 8192   // Buffer length. Note - This isn't how much data we're actually sending.

extern int errno;

/* Signal action */
int cont = 1;

void signalHndl(int tmp)
{
    cont = 0;
}

/* Checksum function */
unsigned short csum(unsigned short *buf, int nwords)
{
    unsigned long sum;

    for (sum = 0; nwords > 0; nwords--)
    {
        sum += *buf++;
    }

    sum = (sum >> 16) + (sum & 0xffff);
    sum += (sum >> 16);

    return (unsigned short) (~sum);
}

int main(int argc, char *argv[])
{
    // Check argument count.
    if (argc < 5)
    {
        fprintf(stdout, "Usage: %s <Source IP> <Source Port> <Destination IP> <Destination Port> [<Time out> <Data>]", argv[0]);

        exit(1);
    }

    // Initialize variables.
    char buffer[PCKT_LEN];
    char recvBuffer[PCKT_LEN];

    struct iphdr *iphdr = (struct iphdr *) buffer;
    struct udphdr *udphdr = (struct udphdr *) (buffer + sizeof(struct iphdr));
    char *pcktData = (char *) (buffer + sizeof(struct iphdr) + sizeof(udphdr));

    int sockfd;
    struct sockaddr_in sin;
    struct sockaddr_in din;
    int one = 1;
    int addrLen = sizeof(din);
    int data = 0;

    struct timeval tv;

    // Timeout
    int timeout = 1;

    if (argc > 5)
    {
        timeout = atoi(argv[5]);
    }

    // Set timeval structure to timeout.
    tv.tv_sec = timeout;
    tv.tv_usec = 0;

    // Set packet buffer to 0's.
    memset(buffer, 0, PCKT_LEN);

    // Check for data.
    int pcktDataLen = 0;

    if (argc > 6)
    {
        // Adds data to the packet's payload (after IP + UDP headers).
        for (int i = 0; i < strlen(argv[6]); i++)
        {
            *pcktData++ = argv[6][i];

            pcktDataLen++;
        }
    }

    // Fill out source sockaddr in (IPv4, source address, and source port).
    sin.sin_family = AF_INET;
    sin.sin_addr.s_addr = inet_addr(argv[1]);
    sin.sin_port = htons(atoi(argv[2]));
    memset(&sin.sin_zero, 0, sizeof(sin.sin_zero));

    // Let's fill out the IP and UDP headers C:

    // IP Header.
    iphdr->ihl = 5;
    iphdr->version = 4;
    iphdr->tos = 16;
    iphdr->tot_len = sizeof(struct iphdr) + sizeof(struct udphdr) + pcktDataLen;
    iphdr->id = htons(54321);
    iphdr->ttl = 64;
    iphdr->protocol = IPPROTO_UDP;
    iphdr->saddr = inet_addr(argv[1]);
    iphdr->daddr = inet_addr(argv[3]);

    // UDP Header.
    udphdr->uh_sport = htons(atoi(argv[2]));
    udphdr->uh_dport = htons(atoi(argv[4]));
    udphdr->len = htons(sizeof(struct udphdr) + pcktDataLen);

    // IP Checksum.
    iphdr->check = csum((unsigned short *)buffer, sizeof(struct iphdr) + sizeof(struct udphdr));

    // Create the socket.
    sockfd = socket(PF_INET, SOCK_RAW, IPPROTO_UDP);

    // Check for socket error.
    if (sockfd <= 0)
    {
        fprintf(stderr, "Socket Error - %s\n", strerror(errno));
        perror("sockfd");

        exit(1);
    }

    // Set socket timeout.
    if (setsockopt(sockfd, SOL_SOCKET, SO_RCVTIMEO, (const char *)&tv, sizeof(tv)) < 0)
    {
        fprintf(stderr, "Socket Option Error (Timeout) - %s\n", strerror(errno));
        perror("setsockopt");

        exit(1);
    }

    // Let the socket know we want to pass our own headers.
    if (setsockopt(sockfd, IPPROTO_IP, IP_HDRINCL, &one, sizeof(one)) < 0)
    {
        fprintf(stderr, "Socket Option Error (Header Include) - %s\n", strerror(errno));
        perror("setsockopt");

        exit(1);
    }

    // Setup signal.
    signal(SIGINT, signalHndl);

    // Let the client know what we're doing.
    fprintf(stdout, "Sending packets to %s:%u from %s:%u with timeout %d\n\n", argv[3], atoi(argv[4]), argv[1], atoi(argv[2]), timeout);

    // Loop.
    while(cont)
    {
        // Send packet.
        fprintf(stdout, "Sending UDP packet.\n");

        // Check for send error.
        if (sendto(sockfd, buffer, iphdr->tot_len, 0, (struct sockaddr *)&sin, sizeof(sin)) <= 0)
        {
            fprintf(stderr, "Error sending packet...\n\n");
        }

        // Receive data that may be coming back to us.
        data = recvfrom(sockfd, recvBuffer, PCKT_LEN, 0, (struct sockaddr *)&din, &addrLen);

        // Check if the IP we're receiving from matches the destination IP along with data check. Keep in mind if you actually spoof the IP, you won't receive any data from the server since it'll reply to the spoofed IP instead :P
        if (din.sin_addr.s_addr != inet_addr(argv[3]) || data < 0)
        {
            fprintf(stderr, "Error receiving packet...\n\n");
        }

        sleep(1);
    }

    // Close socket.
    close(sockfd);

    // Exit program successfully.
    exit(0);
}

 

I still plan to make a program that forwards traffic to a destination in the near future for both TCP and UDP traffic.

 

Thank you.

Share this post


Link to post
Share on other sites




×
×
  • Create New...