教你編程實現TFTP協議


轉載於 : http://blog.sina.com.cn/s/blog_4b0bee65010007d3.html

  不論你是熱衷於黑客技術的愛好者, 還是從事編寫網絡應用程序的程序員, 都需要掌握熟練的編程能力, 以及具備扎實的TCP/IP協議的扎實基礎。很多初學者都有這樣的經歷,要么是能編一些復雜算法的程序,卻不能結合到實際的應用中, 要么就是三卷W.Richard Stevens的聖經《TCP/IP詳解》熟記於胸, 卻無法用熟悉的編程語言將其實現。這真是件很令人郁悶的事。出於這樣的目的, 本文就結合TCP/IP協議中的TFTP協議來分析,並簡單實現了Windows下TFTP的服務器和客戶端。

(致編者: 請務必加上以下聲明)


注: 本文大部分理論引用於<TCP/IP詳解卷一>和中國協議分析網www.cnpaf.net
一、協議分析:
TFTP(Trivial File Transfer Protocol)即簡單文件傳送協議, 是TCP/TP協議族中的一個用來在客戶機與服務器之間進行簡單文件傳輸的協議, 提供不復雜的, 開銷不大的文件傳輸服務.為了保持簡單和短小, TFTP使用UDP協議, 且默認端口號為69,它不提供可靠的數據流傳輸服務, 也不提供存取授權與認證機制, 使用超時重傳方式來保證數據的到達。與FTP相比, TFTP的大小要小的多, 它主要用於小文件的傳輸, 只能從文件服務器上獲得或寫入文件, 不能列出目錄。更多的資料可以參考RFC1350。下面給出了5種TFTP報文格式。
我們可以看到,TFTP報文的頭兩個字節表示操作碼。對於讀請求(RRQ)和寫請求(WRQ),文件名字段說明客戶要讀或寫的位於服務器上的文件。這個文件字段以0字節作為結束。模式字段是一個ASCII碼串netascii或octet(大小寫可任意組合),同樣以0字節結束。netascii表示數據是以成行的ASCII碼字符組成,以兩個字節—回車字符后跟換行字符(稱為CR / LF)作為行結束符。這兩個行結束字符在這種格式和本地主機使用的行定界符之間進行轉化。octet則將數據看作8 bit一組的字節流而不作任何解釋。
每個數據分組包含一個塊編號字段,它以后要在確認分組中使用。以讀一個文件作為例
子,TFTP客戶需要發送一個讀請求說明要讀的文件名和文件模式( mode )。如果這個文件能被這個客戶讀取,TFTP服務器就返回一個塊編號為1的數據分組。TFTP客戶又發送一個塊編號為1的ACK。TFTP服務器隨后發送塊編號為2的數據。TFTP客戶發回塊編號為2的ACK。重復這個過程直到這個文件傳送完。除了最后一個數據分組可含有不足512字節的數據,其他每個數據分組均含有512字節的數據。當TFTP客戶收到一個不足512字節的數據分組,就知道它收到最后一個數據分組。
在寫請求的情況下,TFTP 客戶發送WRQ指明文件名和模式。如果該文件能被該客戶寫,TFTP 服務器就返回塊編號為0的ACK包。該客戶就將文件的頭512字節以塊編號為1發出。服務器則返回塊編號為1的ACK。
最后一種TFTP報文類型是差錯報文,它的操作碼為5。它用於服務器不能處理讀請求或寫請求的情況。在文件傳輸過程中的讀和寫差錯也會導致傳送這種報文,接着停止傳輸。差錯編號字段給出一個數字的差錯碼,跟着是一個ASCII表示的差錯報文字段,可能包含額外的操作系統說明的信息
根據圖一及上面的分析,我們可以得到以下定義:
#define TFTP_RRQ 01 // 讀請求
#define TFTP_WRQ 02 // 寫請求
#define TFTP_DATA 03 // 數據包
#define TFTP_ACK 04 // 確認包
#define TFTP_ERROR 05 // 錯誤代碼

頭文件結構也能很容易得到:
typedef struct tftphdr {
USHORT tu_opcode; // 操作碼
union
{
USHORT tu_block; // 塊號
USHORT tu_code; // 錯誤碼
char tu_stuff[1]; // 請求包填充物
}th_u;
char th_data[1]; // 數據或錯誤字符串
}TFTP_HDR, *PTFTP_HDR;

二、TFTP服務器的實現
不知道大家對兩年前的沖擊波病毒Msblast.exe是否還有印象,該病毒通過RPC遠程溢出漏洞溢出目標主機后,會綁定目標主機的4444端口,然后利用Windows系統自帶的tftp客戶端程序發送下載消息,目標主機通過tftp下載病毒再運行病毒,反復循環導致更多的計算機受到感染。因為Windows系統並沒有默認的TFTP服務端程序,所以此時的關鍵就在於Msblast.exe病毒本身就是個tftp服務器。至於TFTP服務器的實現,以前ww0830在《黑防》介紹過,為了滿足大多數讀者的要求,及關系到本文的完整性,我這里也給出具體實現,注意,本TFTP服務端只實現了供客戶端程序下載的功能,更多的功能讀者可以自己完善。
下面給出TFTP實現核心代碼及詳細注釋
(注: 以下所有代碼均在WindowsXP SP1+VC6.0環境下編譯通過, 因為主要理解思路, 省略了錯誤處理等步驟,完整源代碼見附件內容):

初始化Winsock庫, 注意在要加上ws2_32.lib庫文件:
WSADATA WSAData;
WSAStartup(MAKEWORD(2, 2), &WSAData);

創建套接字
SOCKET sock = INVALID_SOCKET;
sock = socket(AF_INET, SOCK_DGRAM, 0); // 這里用的是UDP協議,所以協議類型為//SOCK_DGRAM
初始化本地主機地址信息:
struct sockaddr_in ServerAddr;
ServerAddr.sin_family = AF_INET;
ServerAddr.sin_addr.s_addr = inet_addr(MyIp); // MyIp為本主機IP
ServerAddr.sin_port = htons(69); // TFTP服務器默認端口號

綁定套接字
bind(sock,(struct sockaddr *)&ServerAddr, sizeof(struct sockaddr_in) )

初始化遠程地址信息
struct sockaddr_in Client;
Client.sin_family = AF_INET;
Client.sin_port = htons(INADDR_ANY);
Client.sin_addr.s_addr = inet_addr(RemoteIp); // 遠程IP地址

定義TFTP首部緩沖區
TFTP_HDR RecvBuff; // 接收的數據緩沖區
TFTP_HDR LocalBuff;// 本地數據緩沖區

接收數據,定義數據塊大小為512字節:
int alen = sizeof(Client);
recvfrom(sock, (char *)&RecvBuff, 512, 0, (struct sockaddr *)&Client, &alen);

獲得客戶端的請求操作碼
LocalBuff.tu_opcode = ntohs(RecvBuff.tu_opcode);

打開本地文件
fp = fopen("abc.txt", "rb"); // 假設abc.txt 為服務器文件
讀本地文件
fread(FileBuff,sizeof(char),512,fp);
填充TFTP首部
SendBuff.tu_opcode = htons(3); // 操作碼3 = data
SendBuff. th_u.tu_block = htons(time); // 塊號
memcpy( &(SendBuff.th_data), FileBuff, i); // 數據

發送文件給客戶機(接收文件或數據類似)
sendto(sock, (char *)&SendBuff, i+4, MSG_DONTROUTE, (struct sockaddr *)&Client, sizeof(Client) );

整個簡單的TFTP服務器這樣就完成了,是不是很簡單吶。
帶外說一說,這里如果要模擬沖擊波病毒的傳播方式,程序最開始有個隨機掃描的代碼:
WSAStartup(MAKEWORD(2, 2), &WSAData);
SOCKADDR_IN addr;
sock = socket(AF_INET, SOCK_STREAM, 0);
addr.sin_family = AF_INET;
addr.sin_port = htons(80); // 通過80端口是否開放判斷對方主機是否存活
addr.sin_addr.s_addr = inet_addr(RemoteIp); // 這里的RemoteIp應該通過一
//個隨機生成網段內IP地址的函數得到
if(connect(sock,(struct sockaddr *) &addr, sizeof(addr))<0)
{
  closesocket(sock);
  WSACleanup();
  return ; //連接失敗,停止掃描
}
// 通過gethostsocket()獲取連出去的ip
struct sockaddr_in hostname;
int namelen = sizeof(hostname);
char * source;
getsockname(sock, (struct sockaddr *)&hostname, &namelen);
source = inet_ntoa( hostname.sin_addr );

這一段代碼的作用是循環連接網段內存活主機的80端口,如果發現某台主機存活,則蠕蟲自身生成的TFTP服務器則接受被沖擊波病毒溢出的客戶端下載請求,復制自身到對方主機,如此惡性循環,導致蠕蟲成級數性的擴散。

三、TFTP客戶端的實現
通常情況下,Windows2K以上操作系統都可以使用系統自帶的TFTP客戶端程序,但自從Msblast.exe蠕蟲爆發后,很多用戶都關掉了TFTP的默認使用。對於很多學習入侵和滲透的人來說,這真是個噩耗^_^。所以,通常很多木馬或后門的設計者都在他們的作品里加入了FTP,Http下載,Email或TFTP客戶端的功能,以加強對肉雞的控制。下面,我們就來分析一下TFTP的客戶端實現。
TFTP客戶端的實現主要體現在對TFTP各種數據包首部字段的分析及填充上。下面給出了部分核心功能的偽代碼,(具體代碼可以參看附件里的源代碼:該代碼作者為helloworld1,在此對他所提供的源代碼表示萬分感謝)

填充(讀/寫)請求字段,可以得到下面的讀/些 請求數據包格式:

於是,定義一個makereq()函數來填充請求字段:
int makereq(char type,int mode,char *filename,char *buffer,int size)
{
  int pos = 0; // 位置
  int i = 0;
  char s[32] = "";
  if(mode==TFTP_NETASCII) // 傳輸模式
    strcpy(s,"netascii");
  else
    strcpy(s,"octet");
  buffer[pos] = 0;
  pos++;
  buffer[pos] = type; // Opcode = 01(RRQ) or 02(WRQ)
  pos++;
  
  for(i=0;i<strlen(filename);i++) // &buffer[3] = Filename
  {
    buffer[pos] = filename[i];
    pos++;
  }
  buffer[pos] = 0; // 0
  pos++;
  for(i=0;i<strlen(s);i++) // Mode
  {
    buffer[pos] = s[i];
    pos++;
  }
  buffer[pos] = 0; // 0
  pos++;
  retu rn pos; // 返回請求包頭長度
}
下面為ACK包格式及填充地段函數makeack():

int makeack(unsigned short num,char *buffer,int size )
{
  int pos = 0;
  buffer[pos] = 0;
  pos++;
  buffer[pos] = TFTP_ACK; // Opcode = 04
  pos++;
  buffer[pos] = (char)(num>>8); // 塊號2個字節
  pos++;
  buffer[pos] = (char)num;
  pos++;
  return pos;
}

同理,DATA包格式及填充函數makedata()如下:

int makedata(int num,char *data,int datasize,char *buffer,int bufsize)
{
  int pos = 0;
  buffer[pos] = 0;
  pos++;
  buffer[pos] = TFTP_DATA; // Opcode = 03
  pos++;
  buffer[pos] = (char)(num>>8); // Block # 塊號
  pos++;
  buffer[pos] = (char)num;
  pos++;
  memcpy(&buffer[pos],data,datasize); // Data 數據
  pos = pos + datasize;
  
  return pos;
}

實現下載文件,cmd[][256]為自定義的參數數據結構,pcount為參數個數:

代碼的注釋很清楚,其實結合文章開始的理論及圖,再實現就很簡單了。至於上傳(put)文件和下載類似,由於篇幅的原因,大家可以參看源代碼。

實現效果:
首先,tftpServer.exe為我們第2部分介紹實現的TFTP服務端程序,在該程序的同級目錄下放一個名為“abc.txt”的文件,運行tftpd.exe。然后,運行第3部分介紹的TFTP客戶端程序tftpClient.exe,並輸入命令:
#get abc.txt

總結:
對於學習網絡知識也好,學習黑客技術也罷,對於TCP/IP協議的掌握是重中之重,本文討論雖然只是簡單討論TFTP協議的相關理論及實現,但稍微復雜一點的FTP協議,POP3協議,SNMP協議也都可以通過類似的分析來實現的。本人水平有限,本文給出都是思路,實現都簡單的不能再簡單。如有不對之處,請大家給予批評指正。
轉自sourcehe的BLOG


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM