图例:tp-link802.1x认证客户端,需要填入用户名、密码、网卡。
struct NetcardInfo {char name[NET_CARD_NAME_MAX_LENGTH]; // 用于pcap_open_live()函数,格式例: \Device\NPF_{D89BD73E-7192-407B-9871-E315194968F8}char description[NET_CARD_DESCRIPTION_MAX_LENGTH]; // 界面描述,同tp-link表述形式u_char mac[MAC_SIZE]; // 网卡mac地址,用于组二层包头bool is_physical; // 是否物理网卡bool is_wireless; // 是否无线网卡
};
通过函数GetAdaptersInfo遍历所有网卡,去除非物理与无线网卡,界面显示可选择的有线网卡(tp-link未去除,会显示所有网卡,包括无线和虚拟网卡)
具体获取:
sprintf_s(netcard.name, sizeof(netcard.name) - 1, "\\Device\\NPF_%s", adapter->AdapterName);
sprintf_s(netcard.description, sizeof(netcard.description) - 1, adapter->Description);
for (UINT i = 0; i < adapter->AddressLength && i < 6; ++i) {netcard.mac[i] = adapter->Address[i];
}
netcard.is_physical = (strstr(adapter->Description, "PCI") > 0);
netcard.is_wireless = (adapter->Type == 71);
pcap_t* pcap_open_live(char* device, int snaplen, int promisc, int to_ms, char* ebuf);
device: 网卡名,格式 \\Device\\NPF_XXXX,如果传入NULL或"any",对所有接口进行捕获
snaplen: 设置每个数据包的捕捉长度,上限MAXIMUM_SNAPLEN
promisc: 是否打开混杂模式
to_ms: 设置获取数据包时的超时时间(ms)(时间过长导致捕获阻塞函数pcap_next_ex延迟退出?)
char error[PCAP_ERRBUF_SIZE];
handle = pcap_open_live("\\Device\\NPF_XXXX", 65536, 1, 20, error);
char filter[128];std::string src_dst = "dst"; // "src"sprintf_s(filter, "(ether proto 0x888e) and (ether %s host %02x:%02x:%02x:%02x:%02x:%02x)",src_dst.c_str(), mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);struct bpf_program fcode;pcap_compile(adapter_hander_, &fcode, filter, 1, 0xff);pcap_setfilter(adapter_hander_, &fcode);
void ProcessRecvData(Process* processer) {if (!processer) {return;}pcap_t* adapter =processer->GetAdapterHandle();if (!adapter) {return;}struct pcap_pkthdr *header;const unsigned char *captured;while (true) {if (connection_stop) {return;}int ret = pcap_next_ex(adapter, &header, &captured);if (1 == ret) {processer->HandleRecvData(captured);}else {Sleep(20);}}
}//recv_thread = new std::thread(ProcessRecvData, this);
int pcap_sendpacket(pcap_t p, u_char buf, int size);
buf是发送数据包的内容缓冲区首地址,目的mac+源mac+协议类型(802.1x是0x88 8e)+802.1x authentication ...
目的mac:广播mac地址{ 0xff,0xff,0xff,0xff,0xff,0xff }或多播mac地址{ 0x01,0x80,0xc2,0x00,0x00,0x03 },首次收到回复后可保存下ac的mac地址并通过pcap_setfilter设置捕获过滤
client->AP: EAPOL START
AP->client: Request Identity
client->AP: Response Identity
AP->client: Request MD5-challenge EAP || ...
client->AP: Response Legacy Nak // 举例仅支持PEAP
AP->client: Request Protected PEAP
client->AP: Client Hello
...
AP->client: Server Hello
...
client->AP: TLS Data
AP->client: TLS Data
...
AP->client: Repeat // 可能出现
client->AP: Response
AP->client: Success
struct PeapPara {Tls* tls;u_char *in_buf;u_char *out_buf;int written;int read;int phase;u_char tk[PEAP_TLV_TK_LEN];u_char ipmk[PEAP_TLV_IPMK_LEN];u_char nonce[PEAP_TLV_NONCE_LEN];ChapMs chap;
};
加密数据分为TLS与CHAP-MS两层,TLS使用BIO_read && BIO_write读写,CHAP-MS需要单独类处理,建议参考PPP协议的开源代码
交互流程中,最后可能存在一步Repeat
调试过程中,经过解密的TLS数据,根据首位EAP type的值,分为IDentity,Tls,MsChapV2处理,然而最后一步Response Identity 后一直返回failure。查找资料才知道这边是AP要求重复Request的值,详细参考Packet15
802.1X协议及Radius协议(二)
IEEE 802.1X-PEAP认证过程分析(抓包)
最详细的802.1x认证原理及eap-md5的认证授权计费
SSL双向认证的认证模式设置问题
EAP-MSCHAPv2
EAP-PEAP with Mschapv2: Decrypted and Decoded
microsoft's PEAP version 0 (Implementation in Windows XP SP1)
PPP协议
以上是WIFI连接的抓包
流程与有线连接基本相同,不过每个包的802.1x WIFI头较有线的源mac目的mac复杂一些
也许去除二层头后处理逻辑可以复用?
留待后续学习后解答...
上一篇: 城乡统筹会议讲话