Search code examples
network-programmingscapypacketpacket-injection

Monitor mode / packet injection not working


I'm trying to inject a packet to the wifi network in monitor mode using scapy. Here is my code

from scapy.all import *
 
class Dot11EltRates(Packet):
    """ Our own definition for the supported rates field """
    name = "802.11 Rates Information Element"
    # Our Test STA supports the rates 6, 9, 12, 18, 24, 36, 48 and 54 Mbps
    supported_rates = [0x0c, 0x12, 0x18, 0x24, 0x30, 0x48, 0x60, 0x6c]
    fields_desc = [ByteField("ID", 1), ByteField("len", len(supported_rates))]
    for index, rate in enumerate(supported_rates):
        fields_desc.append(ByteField("supported_rate{0}".format(index + 1),
                                     rate))
src = "4c:5e:0c:11:01:95"
dst = "d0:39:57:b8:a8:bf"
packet = Dot11(
    addr1=src,
    addr2=dst,
    addr3=src) / Dot11AssoReq(
            cap=0x1100, listen_interval=0x00a) / Dot11Elt(
                ID=0, info="MY_BSSID")
    packet /= Dot11EltRates()
    sendp(packet, iface="wlan0mon")
    packet.show()

I checked the rates on both wifi cards using iw list

Also, both cards support monitor mode and packet injection: checked with aircrack-ng suite sudo aireplay-ng <interface> --test - both show

Injection is working!

And yet, when I inject a packet with one card its only visible on that computer, the other doesn't see it (I'm using wireshark for this), I have set both wifi cards to the same channel and baudrate.

What am I missing?


Solution

  • Okay, I'm happy to share the solution that I came up with. Its in C, I'm using raw sockets and radiotap header to craft a legal packet. The networking cards that I initially used did not fully support packet injection. So, now im using Atheros AR9271 to inject packets and Realtek RTL8812BU for sniffing. Anyways here is the injection code:

    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    #include <unistd.h>
    #include <sys/socket.h>
    #include <netinet/in.h>
    #include <arpa/inet.h>
    #include <netinet/ip.h>
    #include <net/if.h>
    #include <linux/if_packet.h>
    #include <net/ethernet.h>
    #include <sys/ioctl.h>
    #include <openssl/rand.h>
    
    struct radiotap_header
    {
        unsigned char it_version;
        unsigned char it_pad;
        unsigned short it_len;
        unsigned int it_present;
    };
    
    struct ieee80211_header
    {
        unsigned short frame_control;
        unsigned short duration_id;
        unsigned char addr1[ETHER_ADDR_LEN];
        unsigned char addr2[ETHER_ADDR_LEN];
        unsigned char addr3[ETHER_ADDR_LEN];
        unsigned short seq_ctrl;
    };
    
    int main(int argc, char *argv[])
    {
        if (argc != 2)
        {
            fprintf(stderr, "Usage: %s <interface>\n", argv[0]);
            return 1;
        }
    
        int sockfd;
        struct sockaddr_ll sll;
        char *interface = argv[1];
    
        sockfd = socket(AF_PACKET, SOCK_RAW, 0); 
        if (sockfd < 0)
        {
            perror("socket");
            return 1;
        }
    
        struct ifreq if_idx;
        memset(&if_idx, 0, sizeof(struct ifreq));
        strncpy(if_idx.ifr_name, interface, IFNAMSIZ - 1);
        if (ioctl(sockfd, SIOCGIFINDEX, &if_idx) < 0)
        {
            perror("ioctl");
            return 1;
        }
    
        memset(&sll, 0, sizeof(sll));
        sll.sll_family = AF_PACKET;
        sll.sll_ifindex = if_idx.ifr_ifindex;
        sll.sll_protocol = htons(ETH_P_ALL);
        if (bind(sockfd, (struct sockaddr *)&sll, sizeof(sll)) < 0)
        {
            perror("bind");
            return 1;
        }
    
        struct radiotap_header radiotap_hdr;
        radiotap_hdr.it_version = 0;
        radiotap_hdr.it_pad = 0;
        radiotap_hdr.it_len = 0x08;
        radiotap_hdr.it_present = 0;
    
        struct ieee80211_header wifi_hdr;
        wifi_hdr.frame_control = htons(0x0800);
        wifi_hdr.duration_id = htons(0x0000);
        memset(wifi_hdr.addr1, 0xff, 6); 
        memset(wifi_hdr.addr2, 0x11, 6);
        memset(wifi_hdr.addr3, 0x11, 6);
        wifi_hdr.seq_ctrl = htons(0x0000);
    
        int buffer_size = 1450;
        char *bufferToSend = malloc(buffer_size);
        char *str_to_append = "TestingTestingTesting";
        int str_to_append_len = strlen(str_to_append);
        int packet_size = sizeof(struct radiotap_header) + sizeof(struct ieee80211_header) + buffer_size;
        unsigned char *complete_packet = (unsigned char *)malloc(packet_size);
    
        if (RAND_poll() != 1)
        {
            printf("RAND_poll");
            return 1;
        }
        if (RAND_bytes(bufferToSend, buffer_size) != 1)
        {
            printf("RAND_bytes");
            return 1;
        }
        strncpy(bufferToSend + (buffer_size - str_to_append_len), str_to_append, str_to_append_len);
        strncpy(bufferToSend, str_to_append, str_to_append_len);
    
        memcpy(complete_packet, &radiotap_hdr, sizeof(struct radiotap_header));
        memcpy(complete_packet + sizeof(struct radiotap_header), &wifi_hdr, sizeof(struct ieee80211_header));
        memcpy(complete_packet + sizeof(struct radiotap_header) + sizeof(struct ieee80211_header), bufferToSend, buffer_size);
    
        int ret = write(sockfd, complete_packet, packet_size);
        if (ret < 0)
        {
            perror("write");
            return 1;
        }
        
        printf("Packet sent successfully\n");
    
        free(complete_packet);
        free(bufferToSend);
        close(sockfd);
    
        return 0;
    }
    

    And here is the sniffer:

    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    #include <unistd.h>
    #include <signal.h>
    #include <sys/socket.h>
    #include <netinet/in.h>
    #include <arpa/inet.h>
    #include <netinet/ip.h>
    #include <netinet/if_ether.h>
    #include <linux/if_packet.h>
    #include <net/if.h>
    #include <signal.h>
    
    static volatile int keep_running = 1;
    
    void int_handler(int dummy) {
        keep_running = 0;
    }
    
    
    struct radiotap_header
    {
        unsigned char it_version;
        unsigned char it_pad;
        unsigned short it_len;
        unsigned int it_present;
    };
    
    struct ieee80211_header
    {
        unsigned short frame_control;
        unsigned short duration_id;
        unsigned char addr1[6];
        unsigned char addr2[6];
        unsigned char addr3[6];
        unsigned short seq_ctrl;
    };
    
    size_t bytes_received = 0;
    
    void packet_handler(const unsigned char *packet, int packet_len)
    {
        bytes_received += packet_len;
        struct radiotap_header *radiotap_hdr = (struct radiotap_header *)packet;
        struct ieee80211_header *wifi_hdr = (struct ieee80211_header *)(packet + radiotap_hdr->it_len);
        if (packet_len == 1516){
        printf("Packet size: %d\n", packet_len);
    
        printf("==============================================\n");
        printf("Received packet:\n");
        printf("Frame Control: 0x%04x\n", ntohs(wifi_hdr->frame_control));
        printf("Duration ID: %d\n", ntohs(wifi_hdr->duration_id));
        printf("Address 1: %02x:%02x:%02x:%02x:%02x:%02x\n", wifi_hdr->addr1[0], wifi_hdr->addr1[1], wifi_hdr->addr1[2], wifi_hdr->addr1[3], wifi_hdr->addr1[4], wifi_hdr->addr1[5]);
        printf("Address 2: %02x:%02x:%02x:%02x:%02x:%02x\n", wifi_hdr->addr2[0], wifi_hdr->addr2[1], wifi_hdr->addr2[2], wifi_hdr->addr2[3], wifi_hdr->addr2[4], wifi_hdr->addr2[5]);
        printf("Address 3: %02x:%02x:%02x:%02x:%02x:%02x\n", wifi_hdr->addr3[0], wifi_hdr->addr3[1], wifi_hdr->addr3[2], wifi_hdr->addr3[3], wifi_hdr->addr3[4], wifi_hdr->addr3[5]);
        printf("Sequence Control: 0x%04x\n", ntohs(wifi_hdr->seq_ctrl));
        printf("radiotap_hdr->it_len: %d\n", radiotap_hdr->it_len);
        printf("sizeof(struct ieee80211_header): %d\n", sizeof(struct ieee80211_header));
        int payload_start = radiotap_hdr->it_len + sizeof(struct ieee80211_header);
        int payload_size = packet_len - payload_start;
        
        printf("Payload start: %d\n", payload_start);
        printf("Payload size: %d\n", payload_size);
        
        printf("\n\n");
        printf("Payload at start: \n");
        for (int i = payload_start; i < payload_start + 20; i++){
            printf("%c", packet[i]);
        }
    
        printf("\n");
        printf("Payload at end: \n");
        for (int i = payload_size - 20; i < packet_len; i++){
            printf("%c", packet[i]);
        }
    
        printf("\n");
        printf("==============================================\n");
        }
    }
    
    int main(int argc, char *argv[])
    {
        if (argc != 2)
        {
            fprintf(stderr, "Usage: %s <interface>\n", argv[0]);
            return 1;
        }
        signal(SIGINT, int_handler);
    
        int sockfd;
        struct sockaddr_ll sll;
        char buffer[BUFSIZ];
    
        sockfd = socket(AF_PACKET, SOCK_RAW, htons(ETH_P_ALL));
        if (sockfd < 0)
        {
            perror("socket");
            return 1;
        }
    
        memset(&sll, 0, sizeof(sll));
        sll.sll_family = AF_PACKET;
        sll.sll_ifindex = if_nametoindex(argv[1]);
    
        if (sll.sll_ifindex == 0)
        {
            perror("if_nametoindex");
            return 1;
        }
    
        if (bind(sockfd, (struct sockaddr *)&sll, sizeof(sll)) < 0)
        {
            perror("bind");
            return 1;
        }
    
        printf("Listening on %s...\n", argv[1]);
    
        while (keep_running)
        {
            int recv_len = recv(sockfd, buffer, BUFSIZ, 0);
            if (recv_len < 0)
            {
                perror("recv");
                return 1;
            }
    
            packet_handler((unsigned char *)buffer, recv_len);
        }
    
        close(sockfd);
    
        printf("Total bytes received: %zu\n", bytes_received);
    
        return 0;
    }
    

    I'm using openssl random header to generate random bytes for a payload. And for sniffer there is an if in packet_handler that is a filter for only packets of length 1516 (filtering only my injected packets).