网络嗅探与协议分析
分析一款抓包软件
分析的软件名称为winpcap是一款开源的抓包软件。
下面代码为不同协议的格式
// 以太网协议格式的定义
typedef struct ether_header {
u_char ether_dhost[6]; // 目标MAC地址
u_char ether_shost[6]; // 源MAC地址
u_short ether_type; // 以太网类型
}ether_header;
// 用户保存4字节的IP地址
typedef struct ip_address {
u_char byte1;
u_char byte2;
u_char byte3;
u_char byte4;
}ip_address;
// 用于保存IPV4的首部
typedef struct ip_header {
u_char version_hlen; // 首部长度 版本
u_char tos; // 服务质量
u_short tlen; // 总长度
u_short identification; // 身份识别
u_short flags_offset; // 标识 分组偏移
u_char ttl; // 生命周期
u_char proto; // 协议类型
u_short checksum; // 包头测验码
u_int saddr; // 源IP地址
u_int daddr; // 目的IP地址
}ip_header;
// 用于保存TCP首部
typedef struct tcp_header {
u_short sport;
u_short dport;
u_int sequence; // 序列码
u_int ack; // 回复码
u_char hdrLen; // 首部长度保留字
u_char flags; // 标志
u_short windows; // 窗口大小
u_short checksum; // 校验和
u_short urgent_pointer; // 紧急指针
}tcp_header;
// 用于保存UDP的首部
typedef struct udp_header {
u_short sport; // 源端口
u_short dport; // 目标端口
u_short datalen; // UDP数据长度
u_short checksum; // 校验和
}udp_header;
// 用于保存ICMP的首部
typedef struct icmp_header {
u_char type; // ICMP类型
u_char code; // 代码
u_short checksum; // 校验和
u_short identification; // 标识
u_short sequence; // 序列号
u_long timestamp; // 时间戳
}icmp_header;
// 用于保存ARP的首部
typedef struct arp_header {
u_short hardware_type; // 格式化的硬件地址
u_short protocol_type; // 协议地址格式
u_char hardware_length; // 硬件地址长度
u_char protocol_length; // 协议地址长度
u_short operation_code; // 操作码
u_char source_ethernet_address[6]; // 发送者硬件地址
u_char source_ip_address[4]; // 发送者协议地址
u_char destination_ethernet_address[6]; // 目的方硬件地址
u_char destination_ip_address[4]; // 目的方协议地址
}arp_header;
ipv4报文的格式。
TCP报文首部的格式。
UDP报文首部的格式。
ICMP报文首部的格式。用于在IP主机、路由器之间传递控制消息。控制消息是指网络通不通、主机是否可达、路由是否可用等网络本身的消息。
ARP报文格式。arp协议是根据IP地址获取物理地址的一个TCP/IP协议。
判断报文类型
首先根据ethernet_type判断以太网类型,之后逐步分析上层协议类型。
void ethernet_protocol_packet_handle(u_char *arg, const struct pcap_pkthdr *pkt_header, const u_char *pkt_content)
{
ether_header *ethernet_protocol;//以太网协议
u_short ethernet_type; //以太网类型
u_char *mac_string; //以太网地址
//获取以太网数据内容
ethernet_protocol = (ether_header*)pkt_content;
ethernet_type = ntohs(ethernet_protocol->ether_type);
printf("==============Ethernet Protocol=================
");
//以太网目标地址
mac_string = ethernet_protocol->ether_dhost;
printf("Destination Mac Address: %02x:%02x:%02x:%02x:%02x:%02x
",
*mac_string,
*(mac_string + 1),
*(mac_string + 2),
*(mac_string + 3),
*(mac_string + 4),
*(mac_string + 5));
//以太网源地址
mac_string = ethernet_protocol->ether_shost;
printf("Source Mac Address: %02x:%02x:%02x:%02x:%02x:%02x
",
*mac_string,
*(mac_string + 1),
*(mac_string + 2),
*(mac_string + 3),
*(mac_string + 4),
*(mac_string + 5));
printf("Ethernet type: ");
switch (ethernet_type)
{
case 0x0800:
printf("%s", "IP");
break;
case 0x0806:
printf("%s", "ARP");
break;
case 0x0835:
printf("%s", "RARP");
break;
default:
printf("%s", "Unknown Protocol");
break;
}
printf(" (0x%04x)
", ethernet_type);
switch (ethernet_type)
{
case 0x0800:
ip_protocol_packet_handle(arg, pkt_header, pkt_content);
break;
case 0x0806:
arp_protocol_packet_handle(arg, pkt_header, pkt_content);
break;
case 0x0835:
printf("==============RARP Protocol=================
");
printf("RARP
");
break;
default:
printf("==============Unknown Protocol==============
");
printf("Unknown Protocol
");
break;
}
}
根据ip报文中的ip_protocol->proto判断ip协议类型
void ip_protocol_packet_handle(u_char *arg, const struct pcap_pkthdr *pkt_header, const u_char *pkt_content)
{
ip_header *ip_protocol;
sockaddr_in source, dest;
char sourceIP[MAX_ADDR_LEN], destIP[MAX_ADDR_LEN];
ip_protocol = (ip_header*)(pkt_content + 14);
source.sin_addr.s_addr = ip_protocol->saddr;
dest.sin_addr.s_addr = ip_protocol->daddr;
strncpy(sourceIP, inet_ntoa(source.sin_addr), MAX_ADDR_LEN);
strncpy(destIP, inet_ntoa(dest.sin_addr), MAX_ADDR_LEN);
printf("===================IP Protocol==================
");
printf("Version: %d
", ip_protocol->version_hlen >> 4);
printf("Header Length: %d bytes
", (ip_protocol->version_hlen & 0x0f) * 4);
printf("Tos: %d
", ip_protocol->tos);
printf("Total Length: %d
", ntohs(ip_protocol->tlen));
printf("Identification: 0x%.4x (%i)
", ntohs(ip_protocol->identification), ntohs(ip_protocol->identification));
printf("Flags: %d
", ntohs(ip_protocol->flags_offset) >> 13);
printf("---Reserved bit: %d
", (ntohs(ip_protocol->flags_offset) & 0x8000) >> 15);
printf("---Don't fragment: %d
", (ntohs(ip_protocol->flags_offset) & 0x4000) >> 14);
printf("---More fragment: %d
", (ntohs(ip_protocol->flags_offset) & 0x2000) >> 13);
printf("Fragment offset: %d
", ntohs(ip_protocol->flags_offset) & 0x1fff);
printf("Time to live: %d
", ip_protocol->ttl);
printf("Protocol Type: ");
switch (ip_protocol->proto)
{
case 1:
printf("ICMP");
break;
case 6:
printf("TCP");
break;
case 17:
printf("UDP");
break;
default:
break;
}
printf(" (%d)
", ip_protocol->proto);
printf("Header checkSum: 0x%.4x
", ntohs(ip_protocol->checksum));
printf("Source: %s
", sourceIP);
printf("Destination: %s
", destIP);
if (ip_protocol->proto == htons(0x0600))
tcp_protocol_packet_handle(arg, pkt_header, pkt_content);
else if (ip_protocol->proto == htons(0x1100))
udp_protocol_packet_handle(arg, pkt_header, pkt_content);
else if (ip_protocol->proto == htons(0x0100))
icmp_protocol_packet_handle(arg, pkt_header, pkt_content);
}
ARP协议
void arp_protocol_packet_handle(u_char *arg, const struct pcap_pkthdr *pkt_header, const u_char *pkt_content)
{
arp_header *arp_protocol;
arp_protocol = (arp_header*)(pkt_content + 14);
printf("==================ARP Protocol==================
");
printf("Hardware Type: ");
switch (ntohs(arp_protocol->hardware_type))
{
case 1:
printf("Ethernet");
break;
default:
break;
}
printf(" (%d)
", ntohs(arp_protocol->hardware_type));
printf("Protocol Type:
");
switch (ntohs(arp_protocol->protocol_type))
{
case 0x0800:
printf("%s", "IP");
break;
case 0x0806:
printf("%s", "ARP");
break;
case 0x0835:
printf("%s", "RARP");
break;
default:
printf("%s", "Unknown Protocol");
break;
}
printf(" (0x%04x)
", ntohs(arp_protocol->protocol_type));
printf("Hardware Length: %d
", arp_protocol->hardware_length);
printf("Protocol Length: %d
", arp_protocol->protocol_length);
printf("Operation Code: ");
switch (ntohs(arp_protocol->operation_code))
{
case 1:
printf("request");
break;
case 2:
printf("reply");
break;
default:
break;
}
printf(" (%i)
", ntohs(arp_protocol->operation_code));
}
不同报文的处理方式
以UDP协议为例
void udp_protocol_packet_handle(u_char *arg, const struct pcap_pkthdr *pkt_header, const u_char *pkt_content)
{
udp_header *udp_protocol;
udp_protocol = (udp_header*)(pkt_content + 14 + 20);
printf("===================UDP Protocol=================
");
printf("Source Port: %i
", ntohs(udp_protocol->sport));
printf("Destination Port: %i
", ntohs(udp_protocol->dport));
printf("Datalen: %i
", ntohs(udp_protocol->datalen));
printf("Checksum: 0x%.4x
", ntohs(udp_protocol->checksum));
}
icmp中包含两种一种是请求一种是回复
void icmp_protocol_packet_handle(u_char *arg, const struct pcap_pkthdr *pkt_header, const u_char *pkt_content)
{
icmp_header *icmp_protocol;
icmp_protocol = (icmp_header*)(pkt_content + 14 + 20);
printf("==================ICMP Protocol=================
");
printf("Type: %d ", icmp_protocol->type);
switch (icmp_protocol->type)
{
case 8:
printf("(request)
");
break;
case 0:
printf("(reply)
");
break;
default:
printf("
");
break;
}
printf("Code: %d
", icmp_protocol->code);
printf("CheckSum: 0x%.4x
", ntohs(icmp_protocol->checksum));
printf("Identification: 0x%.4x
", ntohs(icmp_protocol->identification));
printf("Sequence: 0x%.4x
", ntohs(icmp_protocol->sequence));
}
wireshark对网站抓包获取账号密码
本次测试的网站为天翼快递网站,步骤如下:
(1)在浏览器中登陆网址:http://www.tykd.com/User/login/
(2)网页打开成功后,运行wireshark,单机开始按钮抓包。
(3)转到网页的登陆界面,输入测试账号和密码登陆。
(4)在wireshark中单机捕获—停止按钮停止抓包,这时对捕获到的许多数据包进行过滤。在过滤器中输入http,此时会显示所有的HTTP报文。
(5)在HTTP中,定义了客户端和服务器交互的不同方法,其中最基本的方法就是GET和POST。GET和POST这两种方法都能用于客户端向服务器提交数据,常用于用户向服务器提交请求的页面路径或者个人信息等,如用户登录信息。在数据包列表中选择info项有POST或者GET字样的数据包,数据详情栏如图所示
(6)在图中可以看出数据包列表中的包含POST的HTTP数据包显示了登录的账号为803213@q.com,密码为231132,说明账号和密码在网络中传输时是明文传输。
之前也尝试着抓了考研帮的网站,但是考研帮采用了特殊的登陆方式,无妨抓取账号密码
抓取app账号密码
采用的是小木虫APP,由于条件所限,电脑无法开热点,使用的安卓虚拟机进行本次实践。
这个app实在坑爹,登陆的时候说该号码未注册,注册的时候显示该号码已经注册,最后选择了在app内使用第三方-考研帮登陆,成功抓取了账号和密码。
值得注意的是在网页端登陆考研帮是无法抓取账号和密码的。