Maicake
Maicake

Reputation: 1126

Netcat doesn' receive udp crafted packet

GOAL: send a crafted udp packet from 127.0.0.1 pport 8090 to localhost port 8091. PROBLEM: the code shown below, as far I can see from wireshark, works in fact I can see my packet exactly with the values I chosen. Anyway if on terminal A I execute nc -ulp 8091 -vv and on terminal B I execute the program, nothing happens. I thought that the string "hhhhhhhhhh" should be visible in the output.
QUESTION: why I can not see the output send by the program?

#include <sys/socket.h>
#include <linux/if_packet.h>
#include <net/ethernet.h> /* the L2 protocols */
#include <netinet/ip.h> 
#include <netinet/udp.h> 
#include <stdio.h>
#include <arpa/inet.h> /* htons */
#include <sys/ioctl.h> 
#include <net/if.h> /* ifreq */
#include <string.h> 
#include <stdlib.h>

#include <linux/seccomp.h> /* seccomp_data */

#define BUF_SIZE 2048 

//http://www.microhowto.info/howto/calculate_an_internet_protocol_checksum_in_c.html#idp22656
uint16_t ip_checksum(void* vdata,size_t length) {
    // Cast the data pointer to one that can be indexed.
    char* data=(char*)vdata;

    // Initialise the accumulator.
    uint32_t acc=0xffff;

    // Handle complete 16-bit blocks.
    for (size_t i=0;i+1<length;i+=2) {
        uint16_t word;
        memcpy(&word,data+i,2);
        acc+=ntohs(word);
        if (acc>0xffff) {
            acc-=0xffff;
        }
    }

    // Handle any partial block at the end of the data.
    if (length&1) {
        uint16_t word=0;
        memcpy(&word,data+length-1,1);
        acc+=ntohs(word);
        if (acc>0xffff) {
            acc-=0xffff;
        }
    }

    // Return the checksum in network byte order.
    return htons(~acc);
}

int main(){

    const char IF[] = "lo"; // modify to change interface
    int sockfd, ifindex, tx_len=sizeof(struct ether_header)+sizeof(struct iphdr)+sizeof(struct udphdr);
    struct ifreq ifr;
    size_t if_name_len;
    char packet[BUF_SIZE];
    struct ether_header *eh;
    struct iphdr *iph;
    struct udphdr *udph; 
    unsigned char *data;
    u_int16_t src_port, dst_port;
    struct sockaddr_ll dst_addr;
    struct seccomp_data sec_payload;
    const char dmac[] = {0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff};
    const char smac[] = {0x00, 0xd0, 0x56, 0xf2, 0xb5, 0x12};

    memset(packet, 0, sizeof(packet));
    eh = (struct ether_header *) packet;
    iph = (struct iphdr *) (packet + sizeof(struct ether_header));
        udph = (struct udphdr *) (packet + sizeof(struct ether_header) + sizeof(struct iphdr));
    data = (char *)packet + sizeof(struct ether_header) + sizeof(struct iphdr) + sizeof(struct udphdr);


    // create raw socket to send/receive ethernet frames that can transport all protocols
    if ((sockfd = socket(AF_PACKET, SOCK_RAW, htons(ETH_P_ALL))) == -1) {
        perror("socket");
    }

    // get interface name length
    if_name_len = strlen(IF);
    if(if_name_len < IF_NAMESIZE) {
        strncpy(ifr.ifr_name, IF, strlen(IF));
        ifr.ifr_name[if_name_len]=0;
    }

    // get the interface index number
    if(ioctl(sockfd, SIOCGIFINDEX, &ifr) == -1){
        perror("ioctl");
    }
        ifindex = ifr.ifr_ifindex;

    // build ethernet header    
        memcpy(eh->ether_dhost, dmac, ETHER_ADDR_LEN);  
        memcpy(eh->ether_shost, smac, ETHER_ADDR_LEN);  
    eh->ether_type = htons(ETH_P_IP);

    // add a struct seccomp_data as data 

    strcpy(data, "hhhhhhhhh");
    tx_len += strlen(data);

    // build ip header
    iph->ihl = 5;
    iph->version = 4;
    iph->tos = 0;
    iph->tot_len = htons(sizeof(struct iphdr) + sizeof(struct udphdr) + strlen(data)); //sizeof(sec_payload)); //20+8+64
    iph->id = htons(54321);
    iph->frag_off = 0x00;
    iph->ttl = 0xFF;
    iph->protocol = IPPROTO_UDP;
    iph->check = 0;
    iph->saddr = inet_addr("127.0.0.1");
    iph->daddr = inet_addr("127.0.0.1");
    iph->check = ip_checksum(iph, iph->ihl << 2); 

    // build udp header 
    udph->source = htons(8090);
    udph->dest = htons(8091);
    udph->len = htons(sizeof(struct udphdr) + strlen(data));//sizeof(sec_payload));
    udph->check = 0;

    memset(&dst_addr, 0, sizeof(struct sockaddr_ll));   
    dst_addr.sll_ifindex = ifr.ifr_ifindex; 
    dst_addr.sll_halen = ETH_ALEN;
    memcpy(dst_addr.sll_addr, dmac, ETH_ALEN);

        if (sendto(sockfd, packet, tx_len, 0, (struct sockaddr*)&dst_addr, sizeof(struct sockaddr_ll)) < 0)
        printf("Send failed\n");
    return 0;
}

Upvotes: 1

Views: 842

Answers (1)

jmm
jmm

Reputation: 69

You used same source and destination ip address. Just changing the source address to fake makes it work. Linux kernel must be dropping the packet, because it doesn't think it originated it.

I've found that on my linux box disabling Reverse Path Filtering for test purposes (sudo sysctl -w 'net.ipv4.conf.all.rp_filter=0') fixed the issue. I was able to send and receive crafted udp packets on same host.

Reverse Path Filtering feature seems to be used for mitigating attacks using ip address spoofing. What may explain why in your case the packet was never delivered to net cat application.

Upvotes: 1

Related Questions