TrisT
TrisT

Reputation: 667

How can I review and possibly alter all raw packets going through my system?

TL;DR

I can already read packets leaving and entering my system. I can also send raw packets. Now I want to, instead of just being able to read, have the power to change incoming/outgoing.


I have used the AF_PACKET, SOCK_RAW and htons(ETH_P_ALL) mix to be able to see all packets that leave or arrive at my system. I've also made a little program to print information about ethernet frame and underlying protocols (I'm on Ubuntu 16.04.3 64-bit using gcc 5.4.0):

#include <linux/if_packet.h>
#include <netinet/ether.h>
#include <net/ethernet.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <sys/types.h>
#include <ifaddrs.h>
#include <string.h>
#include <stdlib.h>
#include <dirent.h>
#include <stdio.h>

#include "/home/bar/Libraries/Colors.h" //color macros (cdefault for default terminal color)
#include "/home/bar/Libraries/BitOperations.h" //Get8/Get16/Get32 (value, from, to)
#include "/home/bar/Libraries/EndianConversions.h" //ToLE16/ToLE32 (value)
#include "/home/bar/Libraries/PacketProtocolDefinitions.h" //network structs and defines (EthernetFrame/IpHeader/TCPHeader/UDP_HeaderLength/ICMP_Descriptors/etc..)

#define BuffLen 0x10000

char iface_count;
char** iface_list;


void workPackets(char* buffer, unsigned int BufferLen){
    struct EthernetFrame* ethernetFrame = (struct EthernetFrame*)buffer;

    char isMine = 0;
    for (int i = 0; i < iface_count; ++i){
        if(!memcmp(iface_list[i], ethernetFrame->source, 6) || !memcmp(iface_list[i], ethernetFrame->destination, 6)){isMine = 1;break;}
    }
    printf("%s  Ethernet Frame: \n\
        Source Mac: %.2x:%.2x:%.2x:%.2x:%.2x:%.2x\n\
        Destination Mac: %.2x:%.2x:%.2x:%.2x:%.2x:%.2x\n\
        Ether Protocol: 0x%.4X\n"cdefault,
    isMine?magenta:green,
    ethernetFrame->source[0], ethernetFrame->source[1], ethernetFrame->source[2], ethernetFrame->source[3], ethernetFrame->source[4], ethernetFrame->source[5], 
    ethernetFrame->destination[0], ethernetFrame->destination[1], ethernetFrame->destination[2], ethernetFrame->destination[3], ethernetFrame->destination[4], ethernetFrame->destination[5],
    ToLE16(ethernetFrame->ethertype));



    //////////////////////////////////////////////////////////////////////////////////////////////////////
    ////////////////////////////////////-------------------IP---------------//////////////////////////////
    //////////////////////////////////////////////////////////////////////////////////////////////////////
    if (ToLE16(ethernetFrame->ethertype) == ethertype_IP)
    {
        struct IpHeader* ipheader = (struct IpHeader*)(buffer+14);
        printf(cyan"    IP header:\n\
        Source IP: %d.%d.%d.%d\n\
        Destination IP: %d.%d.%d.%d\n\
        Total Size: 0x%X\n\
        Protocol: 0x%X\n"cdefault,
        ipheader->source[0], ipheader->source[1], ipheader->source[2], ipheader->source[3],
        ipheader->destination[0], ipheader->destination[1], ipheader->destination[2], ipheader->destination[3],
        ToLE16(ipheader->TotalLength), ipheader->Protocol);



        //<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<//
        //<<<<<<<<<<<<<<-------------TCP----------<<<<<<<<<<<<<//
        //<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<//
        if(ipheader->Protocol == IP_PROTO_TCP){
            struct TCPHeader* tcpheader = (struct TCPHeader*)((void*)ipheader+(ipheader->Version__IHL&0xF)*4);
            printf(cyan"    TCP header:\n\
        Source Port: %u\n\
        Destination Port: %u\n\
        Flags:\n\
            SYN: %s\n\
            ACK: %s\n\
            FIN: %s\n\
        Data Offset: 0x%X\n\
        Sequence Number: %u\n"cdefault,
            tcpheader->source_port, tcpheader->destination_port,
            tcpheader->flags.SYN?"SET":"Zero", 
            tcpheader->flags.ACK?"SET":"Zero",
            tcpheader->flags.FIN?"SET":"Zero",
            Get8(tcpheader->data_offset__NS, 0, 4), tcpheader->sequence_number);
            char* toPrint = (char*)tcpheader;
            unsigned short packet_size = ToLE16(ipheader->TotalLength) - Get8(ipheader->Version__IHL, 4, 8)*4 - Get8(tcpheader->data_offset__NS, 0, 4)*4;
            printf("data(packet size:0x%.2X): %*.*s", packet_size, packet_size, packet_size, toPrint + Get8(tcpheader->data_offset__NS, 0, 4)*4);



        //<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<//
        //<<<<<<<<<<<<<<-------------UDP----------<<<<<<<<<<<<<//
        //<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<//
        }else if (ipheader->Protocol == IP_PROTO_UDP){
            struct UDPHeader* udpheader = (struct UDPHeader*)((void*)ipheader+(ipheader->Version__IHL&0xF)*4);
            printf(cyan"    UDP header:\n\
        Source Port: %u\n\
        Destination Port: %u\n\
        Length: 0x%X\n"cdefault,
            ToLE16(udpheader->source_port), ToLE16(udpheader->destination_port), ToLE16(udpheader->length));
            void* toPrint = (void*)udpheader;
            unsigned short packet_size = ToLE16(udpheader->length) - UDP_HeaderLength;
            printf("data(packet size:0x%.2X) %p: %*.*s",packet_size, toPrint, packet_size, packet_size, (char*)toPrint+UDP_HeaderLength);



        //<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<//
        //<<<<<<<<<<<<<<------------ICMP----------<<<<<<<<<<<<<//
        //<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<//
        }else if(ipheader->Protocol == IP_PROTO_ICMP){
            struct ICMPHeader* icmpheader = (struct ICMPHeader*)((void*)ipheader+(ipheader->Version__IHL&0xF)*4);
            printf(red" ICMP packet: %s\n"cdefault, ICMP_Descriptors[icmpheader->type][icmpheader->code]);
        }



    //////////////////////////////////////////////////////////////////////////////////////////////////////
    ////////////////////////////////////------------------ARP---------------//////////////////////////////
    //////////////////////////////////////////////////////////////////////////////////////////////////////
    }else if (ToLE16(ethernetFrame->ethertype) == ethertype_ARP){
        struct ARPframe* arpframe = (struct ARPframe*)(buffer+14);
        printf(yellow"  ARP %s:\n\
        Sender Mac: %.2X:%.2X:%.2X:%.2X:%.2X:%.2X\n\
        Sender IP: %d.%d.%d.%d\n\
        Target IP: %d.%d.%d.%d\n\
        Target Mac: %.2X:%.2X:%.2X:%.2X:%.2X:%.2X\n"cdefault,
        ToLE16(arpframe->Operation)==2?"reply":"request",
        arpframe->SenderMac[0], arpframe->SenderMac[1], arpframe->SenderMac[2], arpframe->SenderMac[3], arpframe->SenderMac[4], arpframe->SenderMac[5],
        arpframe->SenderIP[0], arpframe->SenderIP[1], arpframe->SenderIP[2], arpframe->SenderIP[3],
        arpframe->TargetIP[0], arpframe->TargetIP[1], arpframe->TargetIP[2], arpframe->TargetIP[3],
        arpframe->TargetMac[0], arpframe->TargetMac[1], arpframe->TargetMac[2], arpframe->TargetMac[3], arpframe->TargetMac[4], arpframe->TargetMac[5]);



    //////////////////////////////////////////////////////////////////////////////////////////////////////
    ////////////////////////////////////-----------------SIZE---------------//////////////////////////////
    //////////////////////////////////////////////////////////////////////////////////////////////////////
    }else if (ToLE16(ethernetFrame->ethertype) <= 0x5DC){
        if(!memcmp(ethernetFrame->source, MAC_STPorLLDP, 6)||!memcmp(ethernetFrame->destination, MAC_STPorLLDP, 6)){
            if(ethernetFrame->ethertype != ethertype_LLDP){
                printf(blue"    STP Packet\n");
            }else{
                printf(blue"    LLDP Packet\n");
            }
        }else{
            printf(red" Unknown Packet Type: Provided Packet Size 0x%.4X:\n     ", ToLE16(ethernetFrame->ethertype));
            for (int i = 0; i < BufferLen; ++i)
            {
                printf("%.2X ", buffer[i]&0xFF);
                if(!((i+1)%6)){
                    printf("\n      ");
                }
            }
        }
        printf(cdefault);



    //////////////////////////////////////////////////////////////////////////////////////////////////////
    ////////////////////////////////////-----------------IPv6---------------//////////////////////////////
    //////////////////////////////////////////////////////////////////////////////////////////////////////
    }else if(ToLE16(ethernetFrame->ethertype) == ethertype_IPv6){
        printf(blue"    IPv6 Packet\n"cdefault);
    }
    return;
}


int main(int argc, char const *argv[])
{
    int sock_r;
    unsigned char *buffer = (unsigned char *) malloc(BuffLen); //to receive data
    memset(buffer,0,BuffLen);
    struct sockaddr saddr;
    int saddr_len = sizeof (saddr), buflen;




//--------------------------------------------Get My Macs

    struct ifaddrs *ifap, *ifaptr;
    unsigned char *ptr;

    if (getifaddrs(&ifap) == 0) {
        for(ifaptr = ifap; ifaptr != NULL; ifaptr = (ifaptr)->ifa_next) 
            if(ifaptr->ifa_addr->sa_family == AF_PACKET)
                iface_count++;
        iface_list = malloc(iface_count*sizeof(void*));
        char tempcount = 0;
        for(ifaptr = ifap; ifaptr != NULL; ifaptr = (ifaptr)->ifa_next) {
            if(ifaptr->ifa_addr->sa_family == AF_PACKET){
                iface_list[tempcount] = malloc(6);
                memcpy(iface_list[tempcount++], &(ifaptr->ifa_addr->sa_data[10]), 6);
            }
        }
        freeifaddrs(ifap);
    } else {
        perror("Getifaddrs");
    }

    printf("My interfaces: \n");
    for (int i = 0; i < iface_count; ++i)
    {
        printf("%d: %.2X %.2X %.2X %.2X %.2X %.2X\n", i, 
            iface_list[i][0] & 0xFF, iface_list[i][1] & 0xFF, iface_list[i][2] & 0xFF, 
            iface_list[i][3] & 0xFF, iface_list[i][4] & 0xFF, iface_list[i][5] & 0xFF);
    }

//----------------------------------------------

    sock_r = socket(AF_PACKET,SOCK_RAW,htons(ETH_P_ALL));
    if(sock_r<0)
    {
        perror("SOCKET");
        return -1;
    }printf("socket connected successfully");


    while(1){
        //Receive a network packet and copy in to buffer
        printf("\n//-----------------------//-----------------------//\n");
        buflen=recvfrom(sock_r,buffer,BuffLen,0,&saddr,(socklen_t *)&saddr_len);
        if(buflen<0)
        {
            perror("Receiving");
            return -1;
        }
        workPackets(buffer, buflen);
    }
    for (int i = 0; i < iface_count; ++i){free(iface_list[i]);}
    free(iface_list);

    return 0;
}

Along with this I have the ability to send spoofed packets with any information I desire, by just building those from the ground up.

That's all good, but now I want to be able to review and possibly change all packets coming in and out of my system.

What I mean by this is:
If I for example wanted to be edgy and spoof my mac to 13:37:AF:CO:DE:B8(not sure if that's even valid), I could just find mine in the ethernet frame and change it going out, and do the opposite when coming in.

This would give me a lot of flexibility, if I for example wanted to keep my original MAC/IP for TCP and UDP, but have it spoofed for ARP.
Would be cool to fake being 2 or more different systems at the same time, or even, if doing MiTM, route the traffic through manually while being able to do anything else I want.

Now I've been searching for a bit, and what I've found was netfilter_queue, that seems to be deprecated.
I've also found a kernel netfilter, but if possible I would like to avoid kernel stuff, since I've started using linux only recently and that seems like a pretty big step to take.

In windows there were these system-wide hooks for events like input, which were really intuitive and easy to use, and I was just looking for an equivalent.

Note: I'm doing all this for learning purposes, I do not want to use libraries or frameworks.

So my question is: Is there a valid non-kernel way to scoop up and change packets?

Feel free to request any information you may need or criticize me if you consider I've done something wrong.
Thank you.

Upvotes: 2

Views: 590

Answers (1)

AlexApps99
AlexApps99

Reputation: 3584

Have a look at the non-deprecated APIs for netfilter_queue, specifically the last three entries on the list (Verdict helpers, Config helpers, Netlink message helper functions). This example could also help.

Upvotes: 1

Related Questions