簡體   English   中英

如何查看並可能更改通過我的系統的所有原始數據包?

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

TL;博士

我已經可以讀取離開和進入我系統的數據包。 我也可以發送原始數據包。 現在我想,而不僅僅是能夠閱讀,有能力改變傳入/傳出。


我使用了AF_PACKETSOCK_RAWhtons(ETH_P_ALL)組合來查看所有離開或到達我系統的數據包。 我還編寫了一個小程序來打印有關以太網幀和底層協議的信息(我在 Ubuntu 16.04.3 64 位使用 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;
}

除此之外,我還可以發送帶有我想要的任何信息的欺騙數據包,只需從頭開始構建這些數據包。

這一切都很好,但現在我希望能夠查看並可能更改所有進出我系統的數據包。

我的意思是:
例如,如果我想要前衛並將我的 mac 欺騙到13:37:AF:CO:DE:B8 (不確定這是否有效),我可以在以太網框架中找到我的並將其更改出去,然后執行進來的時候正好相反。

這會給我很大的靈活性,例如,如果我想為 TCP 和 UDP 保留我的原始 MAC/IP,但讓它被 ARP 欺騙。
假裝同時成為 2 個或更多不同的系統會很酷,或者甚至,如果做 MiTM,手動路由流量,同時能夠做我想做的任何其他事情。

現在我一直在尋找一點,我發現的是netfilter_queue ,這似乎已被棄用
我還發現了一個kernel netfilter ,但如果可能的話,我想避免 kernel 的東西,因為我最近才開始使用 linux ,這似乎是一個很大的步驟。

在 windows 中有這些系統范圍的鈎子,用於像輸入這樣的事件,它們非常直觀且易於使用,我只是在尋找一個等價物。

注意:我做這一切都是為了學習,我不想使用庫或框架。

所以我的問題是:是否有一種有效的非內核方式來收集和更改數據包?

如果您認為我做錯了什么,請隨時索取您可能需要的任何信息或批評我。
謝謝你。

查看netfilter_queue的非棄用 API,特別是列表中的最后三個條目(Verdict helpers、Config helpers、Netlink message helper functions)。 這個例子也可以提供幫助。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM