目录
原理
内容
器材(设备、元器件)
步骤
一、Winmail的安装
二、通过foxmail利用wireshark抓包
·抓SMTP包
·抓POP包
三、QT程序实现POP3和SMTP协议抓包
·POP3
·SMTP
(附录)QT中抓POP与SMTP的C语言代码
·POP
`SMTP
1.Window下Winmail邮件服务器安装过程。
2.应用场景分析:
从搭建的环境中利用wireshark捕获数据包,了解命令格式对应关系。
3.POP3与SMTP协议在QT中C语言的实现。
winmail、Wireshark、ubuntu(QT)、foxmail
1.点开下载好的Winmail安装程序
输入密码:
开始安装:
安装完成:
2.点击服务器程序,添加用户
3.打开管理端:
成功连接。
在用户管理界面新添加一个用户zlz1:
4.登陆刚刚添加用户产生的URL
得到web邮箱界面:
1.安装好foxmail后配置foxmail:
2.设置成功后,先写一封信,不要发送,打开wireshark:
3.开始抓包,并且发送邮件,发送完成后,停止抓包。
成功抓到SMTP协议的数据包。
4.分析电子邮件数据包:
(1)第55帧Foxmail向服务器发送HELO指令,表明身份,可以看到Foxmail客户端的主机名:zlz.com。第57帧服务器回复250表示服务器可用。
(2)第58帧与第60帧,可以看到发送邮件的发送者和接收者。
(3)第63、65、66帧在传输数据内容,第65帧服务器回应354 End data with..表示同意接收。
在第66帧可以看到发送邮件的数据大小。(4)第68帧是邮件的账户和主题信息。
(5)第71帧看到域名解析失败。
(6)第72帧断开服务器连接。
5.为什么域名解析失败?百度了一下:
然后听说163可以收到,又试着给自己的163邮箱发了一封邮件(过程抓包):
6. 分析数据包,看到第33帧邮件成功的发送了。
由此百度了一下,原因可能是域名被QQ加黑名单了。
7.查看数据包内容:随便选一个数据包,跟踪TCP流:
可以看到邮件收发用户、邮件主题
base64加密过的邮件内容。
1.使用foxmail登录163账号发现不行,并在163邮箱里收到了一封邮件:
2.百度后尝试在163邮箱设置中设置授权码,以便第三方软件登陆:
3.设置成功后再在Foxmail中添加163账号,使用授权码登陆,并设置为POP3协议:
4.打开wireshark抓包并用自己搭的winmail服务器向163邮箱发一封邮件,发送成功后,在foxmail页面点收取邮件,然后停止抓包:
分析数据包:
(1)第10、13帧可以看到账号和密码都被明文显示了。
服务器响应是由一个单独的命令行组成或多个命令行组成,响应第一行以ASCII文本+OK或-ERR指出相应状态是成功还是失败。
(2)认证成功后,进入处理阶段:
第16帧,主机向服务器发送命令码STAT,服务器向主机发回邮箱的统计资料(第18帧),包括邮件总数和总字节数(20封邮件、共165760个字节)
第19帧,向服务器发送命令码LIST,第20帧服务器返回邮件数量和每个邮件的大小,每个邮件的大小可双击数据包查看:
第21帧,向服务器发送命令码UIDL,第23帧服务器返回邮件数量和每个邮件的唯一标识符:
第24帧,向服务器发送命令码RETR,第25帧,服务器返回由参数标识的邮件的全部文本 ,此时是返回刚刚收到的第20封邮件的文本内容。
第26帧,返回邮件的大小,共1440字节。
第27帧,显示发件人的账号与邮件主题:
第29帧,主机收到邮件确认。
第31帧,向服务器发送QUIT命令码,终止服务。
第32帧,服务器响应OK。会话终止。
依然可以在数据包追踪TCP流中查看到收发件人账号、IP地址、邮件主题以及base64加密后的邮件内容:
1.在QT中写好代码后执行:
2.重新打开一个终端,telnet连接163的POP3服务器:
程序回显:
3.用user和pass命令在终端上输入账号和密码:
得到回显:
4.
stat: 查看邮箱中的邮件数量以及所占用的字节大小
uidl:查看唯一标识符
回显:
retr: 获取编号为msg#的邮件的内容
回显:
quit:断开连接
回显:
1.在QT中写好代码后运行:
2.使用 telnet smtp.163.com 25 命令与请求smtp服务器连接:
得到回显:
3.向服务器发送 ehlo 命令建立连接:
得到回显:
4.发送auth login命令后输入base64加密后的邮箱账号和密码:
得到认证成功的回显:
5.验证成功后,使用 mail from:[email protected]命令输入邮件发送方;
使用rcpt to:[email protected]命令输入邮件收件方;
使用data命令,编写邮件内容;
使用subject:和from:命令标注邮件头的主题和来源;
标注后输入邮件体的具体内容;
输入具体内容后以“.”结束输入。
回显:
成功后可收到邮件:
6.使用quit命令与smtp服务器断开连接:
回显:
源自《网络数据与协议分析》
LIBS += -lpcap -lnids
#include "nids.h"
#include "pcap.h"
#include "libnet.h"
#include "stdio.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;
}
/*
=======================================================================================================================
下面是分析POP3协议的回调函数
=======================================================================================================================
*/
void pop3_protocol_callback(struct tcp_stream *pop3_connection, void **arg)
{
int i;
char address_string[1024];
char content[65535];
char content_urgent[65535];
struct tuple4 ip_and_port = pop3_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 (pop3_connection->nids_state)
{
case NIDS_JUST_EST:
if (pop3_connection->addr.dest == 110)
{
/*POP3客户端和POP3服务器端建立连接 */
pop3_connection->client.collect++;
/* POP3客户端接收数据 */
pop3_connection->server.collect++;
/* POP3服务器接收数据 */
pop3_connection->server.collect_urg++;
/* POP3服务器接收紧急数据 */
pop3_connection->client.collect_urg++;
/* POP3客户端接收紧急数据 */
printf("%sPOP3客户端与POP3服务器建立连接\n", address_string);
}
return ;
case NIDS_CLOSE:
/* POP3客户端与POP3服务器端连接正常关闭 */
printf("--------------------------------\n");
printf("%sPOP3客户端与POP3服务器连接正常关闭\n", address_string);
return ;
case NIDS_RESET:
/* POP3客户端与POP3服务器端连接被RST关闭 */
printf("--------------------------------\n");
printf("%sPOP3客户端与POP3服务器连接被REST关闭\n", address_string);
return ;
case NIDS_DATA:
{
/* POP3协议接收到新的数据 */
char status_code[5];
struct half_stream *hlf;
if (pop3_connection->server.count_new_urg)
{
/* POP3服务器接收到新的紧急数据 */
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)] = pop3_connection->server.urgdata;
printf("%s", address_string);
return ;
}
if (pop3_connection->client.count_new_urg)
{
/* POP3服务器接收到新的紧急数据 */
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)] = pop3_connection->client.urgdata;
printf("%s", address_string);
return ;
}
if (pop3_connection->client.count_new)
{
/* POP3客户端接收到新的数据 */
hlf = &pop3_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, " <--- ");
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 (strstr(strncpy(status_code, content, 4), "+OK"))
printf("操作成功\n");
if (strstr(strncpy(status_code, content, 4), "-ERR"))
printf("操作失败\n");
for (i = 0; i < hlf->count_new; i++)
{
printf("%s", char_to_ascii(content[i]));
}
printf("\n");
if (strstr(content, "\n\r.\n\r"))
printf("数据传输结束\n");
}
else
{
/* POP3服务器接收到新的数据 */
hlf = &pop3_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);
memcpy(content, hlf->data, hlf->count_new);
content[hlf->count_new] = '\0';
if (strstr(content, "USER"))
printf("邮件用户名为\n");
if (strstr(content, "PASS"))
printf("用户密码为\n");
if (strstr(content, "STAT"))
printf("返回统计资料\n");
if (strstr(content, "LIST"))
printf("返回邮件数量和大小\n");
if (strstr(content, "RETR"))
printf("获取邮件\n");
if (strstr(content, "DELE"))
printf("删除邮件\n");
if (strstr(content, "QUIT"))
printf("退出连接\n");
for (i = 0; i < hlf->count_new; i++)
{
printf("%s", char_to_ascii(content[i]));
}
printf("\n");
}
}
default:
break;
}
return ;
}
/*
=======================================================================================================================
主函数
=======================================================================================================================
*/
void main()
{
nids_params.device="eth0";
struct nids_chksum_ctl temp;
temp.netaddr = 0;
temp.mask = 0;
temp.action = 1;
nids_register_chksum_ctl(&temp,1);
if (!nids_init())
/* Libnids初始化 */
{
printf("出现错误:%s\n", nids_errbuf);
exit(1);
}
nids_register_tcp(pop3_protocol_callback);
/* 注册分析POP3协议的回调函数 */
nids_run();
/* 进入循环捕获数据包的状态 */
}
#include "nids.h"
#include "pcap.h"
#include "libnet.h"
#include "stdio.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;
}
/*
=======================================================================================================================
下面是分析SMTP协议的回调函数
=======================================================================================================================
*/
void smtp_protocol_callback(struct tcp_stream *smtp_connection, void **arg)
{
int i;
char address_string[1024];
char content[65535];
char content_urgent[65535];
struct tuple4 ip_and_port = smtp_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 (smtp_connection->nids_state)
{
case NIDS_JUST_EST:
if (smtp_connection->addr.dest == 25)
{
/*SMTP客户端和SMTP服务器端建立连接 */
smtp_connection->client.collect++;
/* SMTP客户端接收数据 */
smtp_connection->server.collect++;
/* SMTP服务器接收数据 */
smtp_connection->server.collect_urg++;
/* SMTP服务器接收紧急数据 */
smtp_connection->client.collect_urg++;
/* SMTP客户端接收紧急数据 */
printf("%sSMTP发送方与SMTP接收方建立连接\n", address_string);
}
return ;
case NIDS_CLOSE:
/* SMTP客户端与SMTP服务器端连接正常关闭 */
printf("--------------------------------\n");
printf("%sSMTP发送方与SMTP接收方连接正常关闭\n", address_string);
return ;
case NIDS_RESET:
/* SMTP客户端与SMTP服务器端连接被RST关闭 */
printf("--------------------------------\n");
printf("%sSMTP发送方与SMTP接收方连接被REST关闭\n", address_string);
return ;
case NIDS_DATA:
{
/* SMTP协议接收到新的数据 */
char status_code[4];
struct half_stream *hlf;
if (smtp_connection->server.count_new_urg)
{
/* SMTP服务器接收到新的紧急数据 */
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)] = smtp_connection->server.urgdata;
printf("%s", address_string);
return ;
}
if (smtp_connection->client.count_new_urg)
{
/* SMTP服务器接收到新的紧急数据 */
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)] = smtp_connection->client.urgdata;
printf("%s", address_string);
return ;
}
if (smtp_connection->client.count_new)
{
/* SMTP客户端接收到新的数据 */
hlf = &smtp_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, " <--- ");
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 (strstr(strncpy(status_code, content, 3), "221"))
printf("连接中止\n");
if (strstr(strncpy(status_code, content, 3), "250"))
printf("操作成功\n");
if (strstr(strncpy(status_code, content, 3), "220"))
printf("表示服务就绪\n");
if (strstr(strncpy(status_code, content, 3), "354"))
printf("开始邮件输入,以\".\"结束\n");
if (strstr(strncpy(status_code, content, 3), "334"))
printf("服务器响应验证\n");
if (strstr(strncpy(status_code, content, 3), "235"))
printf("认证成功可以发送邮件了\n");
for (i = 0; i < hlf->count_new; i++)
{
printf("%s", char_to_ascii(content[i]));
}
printf("\n");
}
else
{
/* SMTP服务器接收到新的数据 */
hlf = &smtp_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);
memcpy(content, hlf->data, hlf->count_new);
content[hlf->count_new] = '\0';
if (strstr(content, "EHLO"))
printf("HELLO命令\n");
if (strstr(content, "QIUT"))
printf("退出连接\n");
if (strstr(content, "DATA"))
printf("开始传输数据\n");
if (strstr(content, "MAIL FROM"))
printf("发送方邮件地址为\n");
if (strstr(content, "RCPT TO"))
printf("接收方邮件地址为\n");
if (strstr(content, "AUTH"))
printf("请求认证\n");
if (strstr(content, "LOGIN"))
printf("认证机制为LOGIN\n");
for (i = 0; i < hlf->count_new; i++)
{
printf("%s", char_to_ascii(content[i]));
}
printf("\n");
if (strstr(content,"\n."))
printf("数据传输结束\n");
}
}
default:
break;
}
return ;
}
/*
=======================================================================================================================
主函数
=======================================================================================================================
*/
void main()
{
nids_params.device="eth0";
struct nids_chksum_ctl temp;
temp.netaddr = 0;
temp.mask = 0;
temp.action = 1;
nids_register_chksum_ctl(&temp,1);
if (!nids_init())
/* Libnids初始化 */
{
printf("出现错误:%s\n", nids_errbuf);
exit(1);
}
nids_register_tcp(smtp_protocol_callback);
/* 注册分析SMTP协议的回调函数 */
nids_run();
/* 进入循环捕获数据包的状态 */
}