Chinaunix
标题:
拦截自己编写的ARP发包程序发出去的ARP包不成功
[打印本页]
作者:
liudeyi545
时间:
2014-12-30 15:43
标题:
拦截自己编写的ARP发包程序发出去的ARP包不成功
本帖最后由 liudeyi545 于 2015-01-05 18:54 编辑
我想实现的功能是:防止本机在中ARP病毒后,病毒向网关发送虚假ARP包,所以拦截本机发出去的ARP包,对其原MAC地址进行比较,如果和本机一致则通过,不一致说明是病毒发出去的,就丢弃。但是没有实现!
内核版本号:3.13.0-43
#define arp_hrd ea_hdr.ar_hrd
#include<linux/module.h>
#include<linux/init.h>
#include<linux/kernel.h>
#include<linux/netfilter.h>
#include<linux/netfilter_ipv4.h>
#include<linux/ip.h>
#include<net/ip.h>
#include<linux/udp.h>
#include<linux/in.h>
#include<linux/skbuff.h>
#include<linux/netdevice.h>
#include<linux/if_ether.h>
#include<linux/if.h>
#include<linux/if_arp.h>
#include<linux/netfilter_arp.h>
unsigned int hook_func(
unsigned int hooknum,//功能函数挂载点
struct sk_buff *skb,//数据包结构体指针
const struct net_device *in,
const struct net_device *out,
int (*okfn)(struct sk_buff *)
)
{
struct arphdr *arp;//定义ARP包结构体
unsigned char *sha,*arp_ptr;
char buf[20];
arp=arp_hdr(skb);//获取数据包ARP头
arp_ptr=(unsigned char*)(arp+1);
//指针偏移找到数据包源MAC地址
sha=arp_ptr;
sprintf(buf,"%02x:%02x:%02x:%02x:%02x:%02x",sha[0],sha[1],sha[2],sha[3],sha[4],sha[5]);
if(strcmp(buf,"dc:0e:a1:e8:94:d6")==0)
{
printk("MATCH!\n");
return NF_ACCEPT;
//若数据包源MAC地址与本机MAC一致则通过
}
else
{
printk("UNMATCH!\n");
//若数据包源MAC地址与本机MAC地址不一致,则丢弃该数据包
return NF_DROP;
}
}
static struct nf_hook_ops nfho={
.hook=hook_func,//注册功能函数
.pf=NFPROTO_ARP,//协议规则
.hooknum=NF_ARP_OUT,//挂载点
.priority=NF_IP_PRI_FIRST,//处理优先级
.owner=THIS_MODULE,//指定模块
};
static int __init hook_init(void)//注册模块
{
if (nf_register_hook(&nfho)) {
printk(KERN_ERR"<0>nf_register_hook() failed\n");
return -1;
}
return 0;
}
static void __exit hook_fini(void)//注销模块
{
nf_unregister_hook(&nfho);
}
module_init(hook_init);
module_exit(hook_fini);
MODULE_LICENSE("GPL");
这个钩子对于自己编写ARP发包程序发出去的ARP包不起作用,不明白为什么?请大家指教!
作者:
tc1989tc
时间:
2014-12-31 19:24
内核版本号
作者:
tc1989tc
时间:
2014-12-31 22:27
直接打印skb->data数据看 是否是你想要的arp报文
作者:
tc1989tc
时间:
2014-12-31 22:32
后者在你的hook函数最前面调用这个函数skb_reset_mac_header(skb); 在进行你后面的操作
作者:
liudeyi545
时间:
2015-01-05 11:20
内核版本号:3.13.0-43
#define arp_hrd ea_hdr.ar_hrd
#include<linux/module.h>
#include<linux/init.h>
#include<linux/kernel.h>
#include<linux/netfilter.h>
#include<linux/netfilter_ipv4.h>
#include<linux/ip.h>
#include<net/ip.h>
#include<linux/udp.h>
#include<linux/in.h>
#include<linux/skbuff.h>
#include<linux/netdevice.h>
#include<linux/if_ether.h>
#include<linux/if.h>
#include<linux/if_arp.h>
#include<linux/netfilter_arp.h>
unsigned int hook_func(
unsigned int hooknum,//功能函数挂载点
struct sk_buff *skb,//数据包结构体指针
const struct net_device *in,
const struct net_device *out,
int (*okfn)(struct sk_buff *)
)
{
struct arphdr *arp;//定义ARP包结构体
unsigned char *sha,*arp_ptr;
char buf[20];
arp=arp_hdr(skb);//获取数据包ARP头
arp_ptr=(unsigned char*)(arp+1);
//指针偏移找到数据包源MAC地址
sha=arp_ptr;
sprintf(buf,"%02x:%02x:%02x:%02x:%02x:%02x",sha[0],sha[1],sha[2],sha[3],sha[4],sha[5]);
if(strcmp(buf,"dc:0e:a1:e8:94:d6")==0)
{
printk("MATCH!\n");
return NF_ACCEPT;
//若数据包源MAC地址与本机MAC一致则通过
}
else
{
printk("UNMATCH!\n");
//若数据包源MAC地址与本机MAC地址不一致,则丢弃该数据包
return NF_DROP;
}
}
static struct nf_hook_ops nfho={
.hook=hook_func,//注册功能函数
.pf=NFPROTO_ARP,//协议规则
.hooknum=NF_ARP_OUT,//挂载点
.priority=NF_IP_PRI_FIRST,//处理优先级
.owner=THIS_MODULE,//指定模块
};
static int __init hook_init(void)//注册模块
{
if (nf_register_hook(&nfho)) {
printk(KERN_ERR"<0>nf_register_hook() failed\n");
return -1;
}
return 0;
}
static void __exit hook_fini(void)//注销模块
{
nf_unregister_hook(&nfho);
}
module_init(hook_init);
module_exit(hook_fini);
MODULE_LICENSE("GPL");
这个钩子对于自己编写ARP发包程序发出去的ARP包不起作用,不明白为什么?请您指教!
回复
4#
tc1989tc
作者:
liudeyi545
时间:
2015-01-05 11:26
现在的程序可以正确打印原MAC地址,但是拦截效果没有实现。
回复
3#
tc1989tc
作者:
anyhit
时间:
2015-01-05 17:26
你这是 自己实现的arptables吗?
要实现什么功能。感觉你逻辑上有点儿混乱吧。out里面arp包源mac肯定与本地一致的吧
作者:
liudeyi545
时间:
2015-01-05 18:25
您好,我想实现的效果是防止本机在中ARP病毒后,本机ARP病毒向网关发送错误的MAC地址,所以拦截本机发出去的ARP包进行分析。
回复
7#
anyhit
作者:
liudeyi545
时间:
2015-01-05 18:39
我在内核中嵌入我编写的这个模块之后,用我自己写的ARP发包程序发出去的虚假ARP包并不能被拦截,而本机发出去的ARP请求包可以被捕获,这个问题困扰了我好久。
回复
7#
anyhit
作者:
tc1989tc
时间:
2015-01-05 19:12
你自己写的arp发送程序是怎么样的?确定是不是经过arp的out hook函数处理了
作者:
liudeyi545
时间:
2015-01-05 19:34
我不是很理解了。。我这个抓包程序应该是可以抓到本机发出去的所有ARP包的吧?我的发包程序发出去的包自然应该被捕获到吧?我理解的是这样的。
下面是我的发包程序:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <unistd.h>
#include <netdb.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <sys/ioctl.h>
#include <netinet/in.h>
#include <net/if.h>
#include <sys/types.h>
#include <asm/types.h>
#include <features.h> /* 需要里面的 glibc 版本号 */
#if __GLIBC__ >= 2 && __GLIBC_MINOR >= 1
#include <netpacket/packet.h>
#include <net/ethernet.h> /* 链路层(L2)协议 */
#else
#include <asm/types.h>
#include <linux/if_packet.h>
#include <linux/if_ether.h> /* 链路层协议 */
#endif
#include <netinet/if_ether.h>
#define INLEN 4
#define MAC_BCAST_ADDR (uint8_t *) "\xff\xff\xff\xff\xff\xff"
void usage_quit(char *arg0);
int get_ifi(char *dev, char *mac, int macln, struct in_addr *lc_addr, int ipln);
void prmac(u_char *ptr);
int main(int argc, char **argv)
{
if(argc != 2)
usage_quit(argv[0]);
int reqfd, recvfd, salen, n;
u_char *mac;
char recv_buf[120], rep_addr[16];
struct in_addr lc_addr, req_addr;
struct sockaddr_ll reqsa, repsa;
struct arp_pkt {
struct ether_header eh;
struct ether_arp ea;
u_char padding[18];
} req;
bzero(&reqsa, sizeof(reqsa));
reqsa.sll_family = PF_PACKET;
reqsa.sll_ifindex = if_nametoindex("eth0");
if((reqfd = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_RARP))) < 0) {
perror("Socket error");
exit(1);
}
mac = (char *)malloc(ETH_ALEN);
bzero(&req, sizeof(req));
if(get_ifi("eth0", mac, ETH_ALEN, &lc_addr, INLEN)) {
fprintf(stderr, "Error: Get host’s information failed\n");
exit(0);
}
char *temparp="00:31:88:0e:00:45";//随便构造的虚假的mac地址
/* 填写以太网头部*/
memcpy(req.eh.ether_dhost, MAC_BCAST_ADDR, ETH_ALEN);
memcpy(req.eh.ether_shost, temparp, ETH_ALEN);
req.eh.ether_type = htons(ETHERTYPE_ARP);
/* 填写arp数据 */
req.ea.arp_hrd = htons(ARPHRD_ETHER);
req.ea.arp_pro = htons(ETHERTYPE_IP);
req.ea.arp_hln = ETH_ALEN;
req.ea.arp_pln = INLEN;
req.ea.arp_op = htons(ARPOP_REQUEST);
memcpy(req.ea.arp_sha, temparp, ETH_ALEN);
memcpy(req.ea.arp_spa, &lc_addr, INLEN);
inet_aton(argv[1], req.ea.arp_tpa);
//下面一直循环发送......
while(1){
if((n = sendto(reqfd, &req, sizeof(req), 0, (struct sockaddr *)&reqsa, sizeof(reqsa))) <= 0) {
perror("Sendto error");
exit(1);
}
printf("Broadcast arp request of %s, %d bytes be sent\n\n", argv[1], n);
sleep(2);
}
recvfd = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_ARP));
bzero(recv_buf, sizeof(recv_buf));
bzero(&repsa, sizeof(repsa));
salen = sizeof(struct sockaddr_ll);
free(mac);
}
int get_ifi(char *dev, char * mac, int macln, struct in_addr *lc_addr, int ipln)
{
int reqfd, n;
struct ifreq macreq;
reqfd = socket(AF_INET, SOCK_DGRAM, 0);
strcpy(macreq.ifr_name, dev);
/* 获MAC地址*/
if(ioctl(reqfd, SIOCGIFHWADDR, ¯eq) != 0)
return 1;
memcpy(mac, macreq.ifr_hwaddr.sa_data, macln);
/* 获iP地址*/
if(ioctl(reqfd, SIOCGIFADDR, ¯eq) != 0)
return 1;
memcpy(lc_addr, &((struct sockaddr_in *)(¯eq.ifr_addr))->sin_addr, ipln);
return 0;
}
void prmac(u_char *ptr)
{
printf(" Peer MAC is: %02x:%02x:%02x:%02x:%02x:%02x\n",*ptr,*(ptr+1),*(ptr+2),*(ptr+3),*(ptr+4),*(ptr+5));
}
void usage_quit(char *arg0)
{
fprintf(stderr, "Usage: %s <query_IP>\n", arg0);
exit(1);
}
回复
10#
tc1989tc
作者:
anyhit
时间:
2015-01-05 19:51
回复
9#
liudeyi545
10楼说的很有道理。
这里分析下可能的原因
你自己发送arp包应该是应用程序socket构造包吧
那么你使用的socket类型是什么? SOCK_RAW?
linux socket有很强大的功能。可以在网络层发包,也可以在链路层发包
而arp其实是网络层协议
若果你在链路层发包,而在网络层过滤,那应该是过滤不掉的
当然以上是猜想没试过。你可以写个链路层发包用iptables一试就知道了。不过按道理肯定是这样的。因为既然在链路层发包,自己构造以太网头 和网络头 那还有什么必要走网络层?
作者:
anyhit
时间:
2015-01-05 19:58
回复
11#
liudeyi545
刚看到你的程序。应该就是链路层构造包引起的。
其实一般arp防御都是做在目的机器上,做在源机器上还真是少见
如果一定要做,估计你只能在驱动里面进行防御了
另外单纯的arp处理一般不能完全杜绝欺骗。因为还可能 有mac转移攻击。一般是arp静态绑定 + 网关或交换机 mac port绑定 就基本解决所有问题了
作者:
anyhit
时间:
2015-01-05 20:09
http: //3y.uu456.com/bp-c31f46ec4afe04a1b071des1-1.html
试试这个发包。sock = socket(AF_INET, SOCK_PACKET, htons(ETH_P_RARP)); 应该这种发包方式是能过滤掉的
不过可能存在 arp数据源mac 跟 以太网头源mac不一致的问题
作者:
liudeyi545
时间:
2015-01-05 20:40
你好,我其实是在开发一款Linux ARP防火墙,想像360一样实现双向拦截,但在做内部发出拦截的时候遇到了这个问题。因为本人对网络了解比较少,不太明白,我的发包程序发出去的包不经过网络层直接是从链路层发出去的吗?如果是这样的话,如果我想彻底拦截本机发出去的所有的包,挂载点又该在哪儿呢?因为如果我只改变我程序发包的位置最后实现拦截是没有意义的,我还是希望彻底拦截本机所有ARP包。我参看了netfilter和iptables的源码,没找到关于挂载点的说明。还望大神指点!
回复
13#
anyhit
作者:
liudeyi545
时间:
2015-01-05 20:48
你好,我刚才经过您的提醒发现了这个问题,我发包程序的ARP包是链路层产生的,而我ARP拦截是在网络层,那如果我想拦截包括链路层产生的包,netfilter提供这样的机制或者挂载点吗?
回复
10#
tc1989tc
作者:
anyhit
时间:
2015-01-06 10:27
回复
15#
liudeyi545
netfilter没用。这个工作在网络最上层
arp 内核模块应该也没用。这个应该工作在网络最底层。走过netfilter之后,ip数据包里的mac构造就是arp模块的事情
而你要做的事情。因为没做过。不好贸然回答。这里有三个 方案,仅供参考,可实现性需你自己验证
1. 做在网络驱动层的tx函数里面。这个肯定是能解决问题的。
但是要处理的事情就很多了。因为不同的网卡对应的驱动可能不一样。而且需要重新编译内核。主要的工作量在于读源码
2.追踪下socket raw的内核代码。看能不能产生灵感
3.你提到了应用层防火墙的事情
那么可否换种思路。应用层采用socket raw统计发出去的arp包。然后如果发现有问题,就报出一个警告。或者看看能否定位发包应用
最后你那个过滤程序 其实更重要的是匹配源ip是否本地的ip。一般攻击都是伪造arp包中的ip。有两种方式1.伪造内网pc的所有源ip发包欺骗网关 2.伪造网关源ip欺骗内网所有pc
因为伪造源mac太难了。mac那么多位很难穷尽。但ip一般就一个网段。254个arp包搞定所有
作者:
btrace
时间:
2023-05-02 12:06
你hook的位置不对,NF_ARP_OUT只能拦截链路层进来的包,没法拦截本机生成的包了。要拦截所有的包,试试egress?
欢迎光临 Chinaunix (http://bbs.chinaunix.net/)
Powered by Discuz! X3.2