IP欺骗之SSH链接

环境

关于路由环境的搭建可以参考这篇博客 Linux路由配置实战(不同网段通信)

最终搭建环境如下:

虚拟机 说明
centos7.0 路由器 172.16.17.196 + 192.168.43.104
windows 7 A 通信A端 192.168.43.79
ubuntu18.04 B1 通信B端 172.16.17.199
ubuntu18.04 B2 通信B端 172.16.17.194

SSH链接

1、通信B端设置SSH的服务端

# debian/deepin/ubuntu
sudo apt install openssh-server
# 启动ssh服务
sudo systemctl start sshd
# 设置ssh开机自启动
sudo systemctl enable sshd

2、通信A端链接(利用putty)
链接B2
在这里插入图片描述

在这里插入图片描述
链接B1
在这里插入图片描述

在这里插入图片描述

IP欺骗配置

通过hook路由器的netfilter防火墙可以实现,具体代码就不粘了,有想学习的同学可以找我私聊
主要代码如下:

改变daddr:

#include <net/ip.h>
#include <net/tcp.h>
#include <linux/in.h>  
#include <linux/ip.h>  
#include <linux/tcp.h>  
#include <linux/udp.h> 
#include <linux/init.h>
#include <linux/inet.h> /*in_aton()*/
#include <linux/kernel.h>
#include <linux/skbuff.h>
#include <linux/module.h>
#include <linux/socket.h>/*PF_INET*/
#include <linux/netdevice.h>
#include <linux/netfilter.h>
#include <linux/netfilter_ipv4.h>/*NF_IP_PRE_FIRST*/
#define ETHALEN 14
#define NIPQUAD(addr)  \
  ((unsigned char *)&addr)[0], \
  ((unsigned char *)&addr)[1],  \
  ((unsigned char *)&addr)[2],  \
  ((unsigned char *)&addr)[3]  
 __be32 sip,dip;
static struct nf_hook_ops nfho1, nfho2;
char tmp_ip[20];//存储初始的目的IP地址 
unsigned int tcpsend(unsigned int hooknum,
                      struct sk_buff *__skb,
                      const struct net_device *in,
                      const struct net_device *out,
                      int (*okfn)(struct sk_buff *))
{
    
    
    struct sk_buff *skb;
    struct net_device *dev;
    struct iphdr *iph;
    struct tcphdr *tcph;
    int tot_len;
    int iph_len;
    int tcph_len;
    skb = __skb;
    if (skb == NULL)
        return NF_ACCEPT;
    iph = ip_hdr(skb);
    if (iph == NULL)
        return NF_ACCEPT;
    tot_len = ntohs(iph->tot_len);
    if (iph->daddr == in_aton("172.16.17.199"))
    {
    
    
      iph_len = ip_hdrlen(skb);/*in ip.h*/
      //skb_pull(skb, iph_len); //skb->data指针定位到了传输层
      //skb_reset_transport_header(skb);//重置首部长度,现在的首部长度包括了的ip首部长度        
	if (iph->protocol == IPPROTO_TCP)
        {
    
    
		printk("daddr change to 172.16.17.194\n");
	   	iph->daddr = in_aton("172.16.17.194");
            tcph = tcp_hdr(skb);
            tcph_len = tcp_hdrlen(skb);
            dev = dev_get_by_name(&init_net, "ens33");
            tcph->check = 0;
            skb->csum = csum_partial((unsigned char *)tcph, tot_len - iph_len, 0);
            tcph->check = csum_tcpudp_magic(iph->saddr,
                                            iph->daddr,
                                            ntohs(iph->tot_len) - iph_len, iph->protocol,
                                            skb->csum);
            iph->check = 0;
            iph->check = ip_fast_csum(iph, iph->ihl);
            skb->ip_summed = CHECKSUM_NONE;
            skb->pkt_type = PACKET_HOST;
            skb->dev = dev;
            //skb_reset_transport_header(skb);
	      //skb_push(skb, iph_len); //在返回之前,先将skb中得信息恢复至原始L3层状态
		//skb_reset_transport_header(skb);
	      //skb_push(skb, ETHALEN);
	      //skb_reset_transport_header(skb);
        }
    }
    return NF_ACCEPT;
}
static int __init filter_init(void)//注册发送的数据包 
{
    
    
    int ret;
    nfho1.hook = tcpsend;
    nfho1.pf = AF_INET;
    nfho1.hooknum = NF_INET_POST_ROUTING;
    nfho1.priority = NF_IP_PRI_FIRST;
    ret = nf_register_hook(&nfho1);
    if (ret < 0)
    {
    
    
        printk("%s\n", "can't modify skb hook!");
        return ret;
    }
    return 0;
}
static void filter_fini(void)
{
    
    
    nf_unregister_hook(&nfho1);
}
module_init(filter_init);
module_exit(filter_fini);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("druid");

改变saddr:

#include <net/ip.h>
#include <net/tcp.h>
#include <linux/in.h>  
#include <linux/ip.h>  
#include <linux/tcp.h>  
#include <linux/udp.h> 
#include <linux/init.h>
#include <linux/inet.h> /*in_aton()*/
#include <linux/kernel.h>
#include <linux/skbuff.h>
#include <linux/module.h>
#include <linux/socket.h>/*PF_INET*/
#include <linux/netdevice.h>
#include <linux/netfilter.h>
#include <linux/netfilter_ipv4.h>/*NF_IP_PRE_FIRST*/

#define ETHALEN 14
#define NIPQUAD(addr)  \
  ((unsigned char *)&addr)[0], \
  ((unsigned char *)&addr)[1],  \
  ((unsigned char *)&addr)[2],  \
  ((unsigned char *)&addr)[3]  
 __be32 sip,dip;
static struct nf_hook_ops nfho2;
char tmp_ip[20];//存储初始的目的IP地址 
unsigned int tcprecv(unsigned int hooknum,
                      struct sk_buff *__skb,
                      const struct net_device *in,
                      const struct net_device *out,
                      int (*okfn)(struct sk_buff *))

{
    
    
    struct sk_buff *skb;
    struct net_device *dev;
    struct iphdr *iph;
    struct tcphdr *tcph;
    int tot_len;
    int iph_len;
    int tcph_len;
    skb = __skb;
    if (skb == NULL)
        return NF_ACCEPT;
    iph = ip_hdr(skb);
    if (iph == NULL)
        return NF_ACCEPT;
    tot_len = ntohs(iph->tot_len);
    if (iph->saddr == in_aton("172.16.17.194"))
    {
    
    
        iph_len = ip_hdrlen(skb);/*in ip.h*/
	  //skb_pull(skb, iph_len); //skb->data指针定位到了传输层
        //skb_reset_transport_header(skb);//重置首部长度,现在的首部长度包括了的ip首部长度
        if (iph->protocol == IPPROTO_TCP)
        {
    
    
        	printk("saddr change to 172.16.17.199\n");  	
		iph->saddr = in_aton("172.16.17.199");
            tcph = tcp_hdr(skb);
            tcph_len = tcp_hdrlen(skb);
            dev = dev_get_by_name(&init_net, "ens33");
            tcph->check = 0;
            skb->csum = csum_partial((unsigned char *)tcph, tot_len - iph_len, 0);
            tcph->check = csum_tcpudp_magic(iph->saddr,
                                            iph->daddr,
                                            ntohs(iph->tot_len) - iph_len, iph->protocol,
                                            skb->csum);
            iph->check = 0;
            iph->check = ip_fast_csum(iph, iph->ihl);
            skb->ip_summed = CHECKSUM_UNNECESSARY;
            skb->pkt_type = PACKET_HOST;
            skb->dev = dev;
            //skb_reset_transport_header(skb);
	      //skb_push(skb, iph_len); //在返回之前,先将skb中得信息恢复至原始L3层状态
		//skb_push(skb, ETHALEN);
	      //skb_reset_transport_header(skb);
        }
    }
    return NF_ACCEPT;
}
static int __init filter_init(void)//注册发送的数据包 
{
    
    
    int ret;
    nfho2.hook = tcprecv;
    nfho2.pf = AF_INET;
    nfho2.hooknum = NF_INET_PRE_ROUTING;
    nfho2.priority = NF_IP_PRI_FIRST;
    ret = nf_register_hook(&nfho2);
    if (ret < 0)
    {
    
    
        printk("%s\n", "can't modify skb hook!");
        return ret;
    }
    return 0;
}
static void filter_fini(void)
{
    
    
    nf_unregister_hook(&nfho2);
}
module_init(filter_init);
module_exit(filter_fini);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("druid");

改变daddr:
注册在ens33网卡(172.16.17.104)的NF_INET_POST_ROUTING上,
改变saddr:
注册在ens33网卡(172.16.17.104)的NF_INET_PRE_ROUTING上,
为甚么要这样做呢,因为这样可以使得网卡内部的源和目的IP地址相同,不然会出错。原理如下:
在这里插入图片描述这样 内部通信都是199
但是ens33网卡却在和194通信

测试

socket尝试

目的 daddr变成172.16.17.194 saddr变成172.16.17.199 目的

在这里插入图片描述
成功

SSH尝试

在这里插入图片描述

成功

错误样例

错误一

从43.79的虚拟机抓包发现,主机会发送回一个RST包
在这里插入图片描述

原因简单,就是发过去的是目的地址是17.198,但是回来的地址却是17.194,说明没有修改好。
但是从宿主机抓包看,却发现saddr与daddr都是194
我认为,应该是43.79的包是在虚拟网卡内部抓的,宿主机的包在虚拟网卡外部抓的。所以虚拟网卡没有改好IP地址的时候,被43.79抓到,改好IP地址后,被宿主机抓到
在这里插入图片描述

改正hooknum与priority设置,导致错误二:

错误二

TCP链接建立成功,但是发送一个包就会出错,有时候建立的时候会出错,有时候发送多个包后会出错,有时候发送keep-alive包会出错
在这里插入图片描述在这里插入图片描述

发现是因为包分段了,分段包会错误
于是卸载netfilter的驱动,进行普通的TCP链接,发现
在这里插入图片描述

在这里插入图片描述

也就是43.79只显示发送了SYN
宿主机抓包显示SYN———SYN+ACK————RST,断定是中间的路由出现问题
重新配置下路由,果然,之后socket各种发包无问题。(是因为隔了几天,重启了下虚拟机,路由需要重新配置下)
再开启netfilter驱动进行IP欺骗,进行socket链接,但是还是会出错,导致错误三

错误三

我打印路由的包可以发现,包过去了,但是没有收回
禁止发送RST包
在这里插入图片描述

但是没用想了下,是不是hook的时机不同导致的?比如,先是PRE再是POST还是网卡绑定有问题?经过长时间遍历,确定问题网卡名字与HOOK时机上,于是有了以下思路
在这里插入图片描述

导致错误四

错误四

tcpdump只能识别出IP包,连SYN包都无法识别,经过反复查证,在ubuntu下载wireshark抓包查看后,终于明白问题。
问题出在netfilter对数据的改动问题:
//skb_pull(skb, …);
//skb_push(skb, …);
//skb_reset_transport_header(skb)
以上函数我没正确的使用,于是造成了数据包无法识别问题,全部注释掉后,成功实现ssh欺骗链接,进入错误五

错误五

SSH链接总时定期断掉,为调试增添麻烦:
改正:
sudo vi /etc/ssh/sshd_config
在这里插入图片描述

60s发一个心跳包,3次不回答后断掉

猜你喜欢

转载自blog.csdn.net/qq_42882717/article/details/112095122