[英]How can I review and possibly alter all raw packets going through my system?
TL;博士
我已經可以讀取離開和進入我系統的數據包。 我也可以發送原始數據包。 現在我想,而不僅僅是能夠閱讀,有能力改變傳入/傳出。
我使用了AF_PACKET
、 SOCK_RAW
和htons(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.