目录
内容
步骤
(一)、FTP原理
(二)、FTP工作方式
(三)、FTP传输模式
(四)、iis搭建ftp服务器(filezilla、win7)
(五)、QT实现C语言捕获FTP包
(六)、Wireshark抓FTP流量包分析
(附录)FTP的C语言代码实现
1、FTP原理
2、FTP工作方式
3、FTP传输模式
4、iis搭建ftp服务器(filezilla)
5、QT实现C语言捕获FTP包
6、Wireshark抓FTP流量包分析
1、FTP(File Transfer Protocol,文件传输协议) 是 TCP/IP 协议组中的协议之一。
FTP协议包括两个组成部分,其一为FTP服务器,其二为FTP客户端。在开发网站的时候,通常利用FTP协议把网页或程序传到Web服务器上。
此外,由于FTP传输效率非常高,在网络上传输大的文件时,一般也采用该协议。
同大多数Internet服务一样,FTP也是一个客户/服务器系统。用户通过一个客户机程序连接至在远程计算机上运行的服务器程序。
2、FTP传输都是通过明文方式,包括用户名和密码,如需传输的安全性,可采用SFTP。
3、FTP有两个过程一个是控制连接,一个是数据传输。因此FTP协议需要两个端口,一个端口是作为控制连接端口,用于发送指令给服务器以及等待服务器响应;另外一个端口用于数据传输端口,主要作用是从客户向服务器发送一个文件,从服务器向客户发送一个文件,从服务器向客户发送文件或目录列表。
一般来讲,控制连接一直保持到客户-服务器连接的全过程,但数据连接可以根据需要随时开启和结束。而通常文件结尾是以关闭数据连接为标志。这意味着对每一个文件传输或目录列表来说都要建立一个全新的数据连接。
FTP支持两种模式,一种方式叫做Standard (也就是 PORT方式,主动方式),一种是 Passive (也就是PASV,被动方式)。
1、主动模式
PORT中文称为主动模式,工作的原理:
(1)FTP客户端连接到FTP服务器的21端口,发送用户名和密码登录;
(2)登录成功后要list列表或者读取数据时,客户端随机开放一个端口(1024以上),发送 PORT命令到FTP服务器,告诉服务器客户端采用主动模式并开放端口;
(3)FTP服务器收到PORT主动模式命令和端口号后,通过服务器的20端口和客户端开放的端口连接,发送数据,原理如下图:
2、被动模式
PASV是Passive的缩写,中文成为被动模式,工作原理:
(1)FTP客户端连接到FTP服务器的21端口,发送用户名和密码登录;
(2)登录成功后要list列表或者读取数据时,发送PASV命令到FTP服务器, 服务器在本地随机开放一个端口(1024以上),然后把开放的端口告诉客户端;
(3)客户端再连接到服务器开放的端口进行数据传输,原理如下图:
注:
·由于防火墙机制,主动模式不利于客户端管理,被动模式不利于服务端管理。
·主动情况下服务端数据端主动链接客户端可能遭到客户端防火墙拦截。
·被动情况下客户端主动访问服务端数据端口可能遭到服务端防火墙拦截。
1、二进制数据传输模式
在二进制传输中,保存文件的位序,以便原始和拷贝的是逐位一一对应的。因此二进制模式常用来传送可执行文件,压缩文件,和图片文件,而且二进制模式比文本模式更快,并可以传输所有ASCII值,所以系统管理员一般将FTP设置成二进制模式。
2、ASCII传输模式
假定用户正在拷贝的文件包含简单的ASCII码文本,在文件传输时ftp通常会自动地调整文件的内容,把文件解释成另外那台计算机存储文本文件的格式。用HTML和文本编写的文件必须用ASCII模式上传,用BINARY模式上传会破坏文件,导致文件执行出错。
·FXP
FXP说简单点就是一个FTP客户端控制两个FTP服务器,在两个FTP服务器之间传送文件。FXP的全称为File Exchange Protocol――文件交换协议,可以认为FXP本身其实就是FTP的一个子集,因为FXP方式实际上就是利用了FTP服务器的Proxy命令,不过它的前提条件是FTP服务器要支持PASV,且支持FXP方式。FXP传送时,文件并不下载至本地,本地只是发送控制命令
·TFTP
TFTP(Trivial File Transfer Protocol)小文件传输协议,它基于UDP协议而实现。它只能从文件服务器上获得或写入文件,不能列出目录,不进行认证,它传输8位数据。传输中有三种模式:netascii,这是8位的ASCII码形式,另一种是octet,这是8位源数据类型;最后一种mail已经不再支持,它将返回的数据直接返回给用户而不是保存为文件。
1、打开控制面板-》程序-》程序和功能-》打开或关闭Windows功能
将IIS全部打钩,点击确定,
等待更改完成。
2、打开iis管理器
在服务器网站下添加FTP站点:
填写站点的名字和物理路径(作为FTP目录的路径):
填写IP和你想用的端口号,可以选择是否使用SSL(在里我就不用了):
授权所有用户权限:
一个FTP站点搭建好了:
通过ftp://IP/可访问自己的FTP站点:
注:
在IIS管理器中禁用匿名身份验证:
此时在FTP上站点下载文件就需要验证:
3、filezilla FTP服务器
FileZilla是一个免费开源的FTP软件,分为客户端版本和服务器版本,具备所有的FTP软件功能。可控性、有条理的界面和管理多站点的简化方式使得Filezilla客户端版成为一个方便高效的FTP客户端工具,而FileZilla Server则是一个小巧并且可靠的支持FTP&SFTP的FTP服务器软件。
FileZilla是一种快速、可信赖的FTP客户端以及服务器端开放源代码程式,具有多种特色、直接的接口。FileZilla在2002年11月获选为当月最佳推荐专案
(关闭刚刚的FTP站点)
·服务器
(1)打开FTPSERV,启动
打开FTP server管理器:
连接到服务器。
(2)添加用户和文件夹,点击人头图标:
添加用户:
设置密码:
(3)设置共享文件夹
并在右侧设置文件的权限。
·客户端
(1)打开FileZilla客户端
左侧是本地文件夹,右侧是服务器文件夹。
(2)输入地址:127.0.0.1,用户名及密码,连接:
网页上也可以访问:
(3)
至此,说明ftp可以正常运行。接下来,则要实现异地访问,利用IP访问,连接不成功。最简单的设置就是把防火墙关了:
打开控制面板—》系统和安全—》Windows防火墙—》打开或关闭防火墙
此时就可以访问了:
1、打开Ubuntu,在QT中新建FTP项目,输入抓取FTP包的C语言代码(附录):
2、运行,并再打开一个终端:
输入ftp,连接ftp,输入用户名和密码。
得到回显:
可以发现,ftp是明文传输。
ls列出文件:
3、使用get命令从服务器下载文件:
得到回显:
4、使用put命令上传文件:
得到回显:
用户没有上传权限所以上传失败。
4.与服务器断开连接
得到回显:
1.数据包分析
(1) 首先,因为ftp是基于tcp传输的,其实是在tcp内部,属于tcp的一部分,只不过是,有了这一部分,我们就吧tcp的数据包认为是ftp的数据包了。
·可看到前三个数据包是tcp的三次握手连接的过程。
·可以看到tcp连接的是ftp服务器的21端口。
(2)FTP命令分析
·经过TCP三次握手建立连接,建立连接成 功后,FTP服务器返回状态码220,表示服务就绪。
·登陆过程首先由终端向FTP服务器发送登陆用户名”anonymous”匿名登陆并等待验证。用户名验证通过后,FTP 服务器返回状态码331,表示用户名验证已通过并需要输入密码。
·终端将登陆密码”[email protected]”发送给FTP服务器,FTP服务器验证后返回状态码 230,表示用户已经登陆。
·终端向FTP服务器发送命令SYST,FTP服务器返回状态码215,表示获取服务器操作系统成功。
·终端向FTP服务器发送命令pwd,表示显示远程计算机当前目录成功。
·终端向FTP服务器发送命令“TYPE I”,表示设置文件传输类型为二进制流,FTP服务器返回状态码 200,表示命令执行成功。
·SIZE: 从服务器上返回指定文件的大小。
·CWD: 改变工作目录。
·PASV: 让服务器在数据端口监听,进入被动模式。
端口号:
·REST: 该命令并不传送文件,而是略过指定点后的数据。此命令后应该跟其它要求文件传输的 FTP 命令。
·RETR: 下载文件。
·STOR: 上传文件。
·QUIT: 关闭与服务器的连接。
2.流分析
(源自《网络数据与协议分析》)
#include
#include
#include
#include "nids.h"
char ascii_string[10000];
char *char_to_ascii(char ch)
{
char *string;
ascii_string[0]=0;
string = ascii_string;
if (isgraph(ch))
*string++ =ch;
else if(ch == ' ')
*string++ = ch;
else if (ch=='\n'|| ch == '\r')
*string++ = ch;
else
*string++ = '.';
*string = 0;
return ascii_string;
}
/*==========================================================================
* FTP call_back
*==========================================================================
*/
void ftp_protocol_callback(struct tcp_stream *ftp_connection, void **arg)
{
int i;
char address_string[1024];
char content[65535];
char content_urgent[65535];
struct tuple4 ip_and_port = ftp_connection->addr;
strcpy(address_string, inet_ntoa(*((struct in_addr*)&(ip_and_port.saddr))));
sprintf(address_string+strlen(address_string),":%i",ip_and_port.source);
strcat(address_string,"<--->");
strcat(address_string, inet_ntoa(*((struct in_addr*)&(ip_and_port.daddr))));
sprintf(address_string + strlen(address_string)," : %i",ip_and_port.dest);
strcat(address_string,"\n");
switch(ftp_connection->nids_state)
{
case NIDS_JUST_EST:
if((ftp_connection->addr.dest == 21)||(ftp_connection->addr.source==20))
{
ftp_connection->client.collect++;
ftp_connection->server.collect++;
ftp_connection->server.collect_urg++;
ftp_connection->client.collect_urg++;
if(ftp_connection->addr.dest==21)
printf("%s FTP server is connected by FTP client \n ",address_string);
if(ftp_connection->addr.source ==20)
printf("%s data tansmission between client and server ");
}
return ;
case NIDS_CLOSE:
printf("-----------------------------------------------\n");
if(ftp_connection->addr.dest ==21)
printf("%s control connection is closed normally \n",address_string);
if(ftp_connection->addr.source==20)
printf("%s data transmission is closed normally\n",address_string);
return;
case NIDS_RESET:
printf("------------------------------------------------\n");
if(ftp_connection->addr.dest==21)
printf("control connection is closed by RST",address_string);
if(ftp_connection->addr.source ==20)
printf("data connection is closed by RST",address_string);
return;
case NIDS_DATA:
{
struct half_stream *hlf;
if (ftp_connection->server.count_new_urg)
{
printf("-------------------------------------------------\n");
strcpy(address_string, inet_ntoa(*((struct in_addr*)&(ip_and_port.saddr))));
sprintf(address_string + strlen(address_string)," : %i",ip_and_port.source);
strcat(address_string,"urgent--->");
strcat(address_string, inet_ntoa(*((struct in_addr*)&(ip_and_port.daddr))));
sprintf(address_string +strlen(address_string),":%i",ip_and_port.dest);
strcat(address_string,"\n");
address_string[strlen(address_string)+1]=0;
address_string[strlen(address_string)]=
ftp_connection->server.urgdata;
printf("%s",address_string);
return;
}
if(ftp_connection->client.count_new_urg)
{
printf("------------------------------------------------------\n");
strcpy(address_string,inet_ntoa(*((struct in_addr*)&(ip_and_port.source))));
sprintf(address_string+strlen(address_string),":%i",ip_and_port.source);
strcat(address_string,inet_ntoa(*((struct in_addr*)&(ip_and_port.daddr))));
sprintf(address_string +strlen(address_string),":%i",ip_and_port.dest);
address_string[strlen(address_string)+1]=0;
address_string[strlen(address_string)]=
ftp_connection->client.urgdata;
printf("%s",address_string);
return;
}
if(ftp_connection->client.count_new)
{
hlf = &ftp_connection->client;
strcpy(address_string,inet_ntoa(*((struct in_addr*)&(ip_and_port.saddr))));
sprintf(address_string+strlen(address_string),":%i",ip_and_port.source);
strcat(address_string,inet_ntoa(*((struct in_addr*)&(ip_and_port.daddr))));
sprintf(address_string +strlen(address_string),":%i",ip_and_port.dest);
strcat(address_string,"\n");
printf("----------------------------------------------------------\n");
printf("%s",address_string);
memcpy(content,hlf->data,hlf->count_new);
content[hlf->count_new]="\0";
if(ftp_connection->addr.source==20)
{
printf("the transmission data is : \n");
for(i=0;icount_new;i++)
{
printf("%s",char_to_ascii(content[i]));
}
printf("\n");
}
else
{
if (content[0] == '1' || content[0] == '2' || content[0] == '3' || content[0] == '4' || content[0] == '5')
printf("FTP服务器响应状态代码为:%c%c%c\n", content[0], content[1], content[2]);
if (strncmp(content, "220", 3) == 0)
printf("新连接的用户的服务已经准备就绪\n");
if (strncmp(content, "110", 3) == 0)
printf("启动标记应答\n");
if (strncmp(content, "120", 3) == 0)
printf("表示 服务在nnn分钟内可用\n");
if (strncmp(content, "125", 3) == 0)
printf("表示数据连接已打开,准备传送\n");
if (strncmp(content, "150", 3) == 0)
printf("表示文件状态正确,正在打开数据连接\n");
if (strncmp(content, "200", 3) == 0)
printf("表示命令正常执行\n");
if (strncmp(content, "202", 3) == 0)
printf("表示命令未被执行,此站点不支持此命令\n");
if (strncmp(content, "211", 3) == 0)
printf("表示系统状态或系统帮助响应\n");
if (strncmp(content, "212", 3) == 0)
printf("表示目录状态信息\n");
if (strncmp(content, "213", 3) == 0)
printf("表示文件状态信息\n");
if (strncmp(content, "214", 3) == 0)
printf("表示帮助信息\n");
if (strncmp(content, "215", 3) == 0)
printf("表示名字系统类型\n");
if (strncmp(content, "221", 3) == 0)
printf("表示控制连接已经被关闭\n");
if (strncmp(content, "225", 3) == 0)
printf("表示数据连接已经打开,没有数据传输\n");
if (strncmp(content, "226", 3) == 0)
printf("表示数据连接已经关闭,请求文件操作成功完成\n");
if (strncmp(content, "227", 3) == 0)
printf("表示进入被动模\n");
if (strncmp(content, "230", 3) == 0)
printf("表示用户已经登录\n");
if (strncmp(content, "250", 3) == 0)
printf("表示请求文件操作已经成功执行\n");
if (strncmp(content, "257", 3) == 0)
printf("表示创建路径名字\n");
if (strncmp(content, "331", 3) == 0)
printf("表示用户名正确,需要输入密码\n");
if (strncmp(content, "332", 3) == 0)
printf("表示 登录时需要帐户信息\n");
if (strncmp(content, "350", 3) == 0)
printf("表示对请求的文件操作需要更多的指令\n");
if (strncmp(content, "421", 3) == 0)
printf("表示服务不可用,关闭控制连接\n");
if (strncmp(content, "425", 3) == 0)
printf("表示打开数据连接操作失败\n");
if (strncmp(content, "426", 3) == 0)
printf("表示关闭连接,中止传输\n");
if (strncmp(content, "450", 3) == 0)
printf("表示请求的文件操作未被执行\n");
if (strncmp(content, "451", 3) == 0)
printf("表示请求操作中止,有本地错误发生\n");
if (strncmp(content, "452", 3) == 0)
printf("表示未执行请求的操作,系统存储空间不足 ,文件不可用\n");
if (strncmp(content, "500", 3) == 0)
printf("表示语法错误,命令错误\n");
if (strncmp(content, "501", 3) == 0)
printf("表示参数的语法错误\n");
if (strncmp(content, "502", 3) == 0)
printf("表示命令未被执行\n");
if (strncmp(content, "503", 3) == 0)
printf("表示命令顺序发生错误\n");
if (strncmp(content, "504", 3) == 0)
printf("表示由于参数而发生错误命令\n");
if (strncmp(content, "530", 3) == 0)
printf("表示未登录\n");
if (strncmp(content, "532", 3) == 0)
printf("表示存储文件需要帐户信息\n");
if (strncmp(content, "550", 3) == 0)
printf("表示未执行请求的操作,文件不可用\n");
if (strncmp(content, "551", 3) == 0)
printf("表示请求操作中止,页面类型未知\n");
if (strncmp(content, "552", 3) == 0)
printf("表示请求的文件操作中止,超出存储分配空间\n");
if (strncmp(content, "553", 3) == 0)
printf("表示未执行请求的操作,文件名不合法\n");
for (i = 0; i < hlf->count_new; i++)
{
printf("%s", char_to_ascii(content[i]));
}
printf("\n");
}
}
else
{
/* FTP服务器接收到新的数据 */
hlf = &ftp_connection->server;
strcpy(address_string, inet_ntoa(*((struct in_addr*) &(ip_and_port.saddr))));
sprintf(address_string + strlen(address_string), ":%i", ip_and_port.source);
strcat(address_string, " ---> ");
strcat(address_string, inet_ntoa(*((struct in_addr*) &(ip_and_port.daddr))));
sprintf(address_string + strlen(address_string), ":%i", ip_and_port.dest);
strcat(address_string, "\n");
printf("--------------------------------\n");
printf("%s", address_string);
/* 输出FTP服务器端接收到的新的数据 */
memcpy(content, hlf->data, hlf->count_new);
content[hlf->count_new] = '\0';
if (ftp_connection->addr.source == 20)
printf("FTP服务器向FTP客户端发送数据\n");
else
{
if (strstr(content, "USER"))
printf("用户名字为(USER):%s\n", content + strlen("USER"));
else if (strstr(content, "PASS"))
printf("用户密码为(PASS):%s\n", content + strlen("PASS"));
else if (strstr(content, "PORT"))
printf("端口参数为(PORT):%s\n", content + strlen("PORT"));
else if (strstr(content, "LIST"))
printf("显示文件列表(LIST):%s\n", content + strlen("LIST"));
else if (strstr(content, "CWD"))
printf("改变工作目录为(CWD):%s\n", content + strlen("CWD"));
else if (strstr(content, "TYPE"))
printf("类型为(TYPE):%s\n", content + strlen("TYPE"));
else if (strstr(content, "RETR"))
printf("获取文件为(RETR):%s\n", content + strlen("RETR"));
else if (strstr(content, "STOR"))
printf("保存文件为(STOR):%s\n", content + strlen("STOR"));
else if (strstr(content, "XRMD"))
printf("删除目录(XRMD):%s\n", content + strlen("XRMD"));
else if (strstr(content, "QUIT"))
printf("退出登陆(QUIT):%s\n", content + strlen("QUIT"));
else printf("FTP客户端使用的命令为 %c%c%c%c\n", content[0], content[1], content[2], content[3]);
}
for (i = 0; i < hlf->count_new; i++)
{
printf("%s", char_to_ascii(content[i]));
}
printf("\n");
}
}
default:
break;
}
return;
}
int main(void)
{
struct nids_chksum_ctl tmp;
tmp.netaddr = 0;
tmp.mask = 0;
tmp.action = 1;
nids_register_chksum_ctl(&tmp, 1);
printf("nids_chksum_ctl:%d\n",tmp.action);
printf("hello -----------------------------------\n");
if (!nids_init())
{
printf("出现错误:%s\n", nids_errbuf);
exit(1);
}
nids_register_tcp(ftp_protocol_callback);
nids_run();
return 0;
}