Firewall
Task 1: Using Firewall
Linux有一个叫做iptables的工具,它本质上是防火墙。 在此任务中,目标是使用iptables设置一些防火墙策略,并在策略生效后观察系统的行为。
Prevent A from doing telnet to Machine B.
本项实验需要用iptables
实现阻挡机器A用telnet
连接机器B,命令如下,在机器A上阻止目的ip是机器B且端口是23的数据包发出。
1 | sudo iptables -A OUTPUT -d 192.168.164.130 -p tcp --dport 23 -j DROP |
如下图,可以看到,连接不能成功
Prevent B from doing telnet to Machine A.
本项实验需要用iptables
实现阻挡机器B用telnet
连接机器A,命令如下,在机器A上阻止来源IP是机器A且端口是23的数据包进入。
1 | sudo iptables -A INPUT -s 192.168.164.130 -p tcp --dport 23 -j DROP |
如下图,可以看到,连接不能成功
Prevent A from visiting an external web site.
You can choose any web site that you like to block, but keep in mind, some web servers have multiple IP addresses.
这里我们选择百度为我们实验的目标网站,我们用iptables
阻挡机器A往www.baidu.com
发包
根据下面图片可以看到,实验前可以打开页面,实验之后页面不能打开。
1 | sudo iptables -A OUTPUT -p tcp -d www.baidu.com --dport 80 -j DROP |
Task 2: Implementing a Simple Firewall
您在前面的任务中使用的防火墙是防火墙的包过滤类型。 这种类型的防火墙的主要部分是过滤部分,它检查每个传入和传出的数据包,并强制执行管理员设置的防火墙策略。 由于包处理是在内核中完成的,所以过滤也必须在内核中完成。 因此,实现这样的防火墙似乎需要我们修改Linux内核。 在过去,这必须通过修改和重建内核来完成。 现代Linux操作系统提供了几种新的机制,以方便在不重建内核映像的情况下操作数据包。 这两种机制是可加载内核模块(LKM)和Netfilter。
LKM允许我们在运行时向内核添加一个新模块。 这个新模块使我们能够扩展内核的功能,而不重建内核,甚至不重新启动计算机。 防火墙的数据包过滤部分可以作为LKM实现。 然而,这还不够。 为了使过滤模块阻止传入/传出数据包,必须将该模块插入到数据包处理路径中。 在Netfilter被引入Linux之前,这是不容易做到的。
Netfilter的设计是为了方便授权用户操作数据包。 Netfilter通过在Linux内核中实现多个钩子来实现这个目标。 这些钩子被插入到各种地方,包括数据包传入和传出路径。 如果我们想操作传入的数据包,我们只需要将我们自己的程序(在LKM内)连接到相应的钩子上。 一旦传入的数据包到达,我们的程序将被调用。 我们的程序可以决定这个数据包是否应该被阻塞;此外,我们还可以修改程序中的数据包。
在此任务中,需要使用LKM和Netfilter来实现包过滤模块。 该模块将从数据结构中获取防火墙策略,并使用策略来决定数据包是否应该被阻塞。 为了让您的生活更轻松,所以您可以专注于过滤部分,防火墙的核心,我们允许您在程序中硬编码防火墙策略。
在用 netfilter
编程的过程中,我们用以下两个函数匹配IP
1 | bool check_address_src(struct iphdr *ip_header, int a, int b, int c, int d) |
然后写过滤数据包的钩子函数,见下面截图,然后是钩子函数的注册和清除,我选择将入口和出口的过滤钩子注册在NF_INET_PRE_ROUTING
和NF_INET_POST_ROUTING
两个位置。
1 | int init_module(void) |
Prevent A from doing telnet to Machine B.
为了实现功能,我们在出口钩子函数实现以下代码,我们判断目的端口是不是23,然后判断目的ip是不是我们的过滤目标。
如图,实验成功,连接不成功,而且在dmesg中看到了右边的记录
Prevent B from doing telnet to Machine A.
为了实现功能,在入口钩子函数里实现以下代码,我们判断目的端口是不是23,然后判断目的和来源ip是不是我们的过滤目标。
如图,实验成功,连接不成功,而且在dmesg中看到了右边的记录
Prevent A from doing ping to Machine B.
为了实现功能,在出口钩子函数里实现以下代码,我们判断协议是不是icmp的请求包
,然后判断目的和来源ip是不是我们的过滤目标。
如图,实验成功,连接不成功,而且在dmesg中看到了右边的记录
Task 3: Evading Egress Filtering
许多公司和学校实施出口过滤,这阻止了他们网络中的用户接触到某些网站或互联网服务。 它们确实允许用户访问其他网站。 在许多情况下,这种类型的防火墙检查传出数据包中的目标IP地址和端口号。 如果一个数据包符合限制,它将被丢弃。 由于性能原因,它们通常不进行深度分组检查(即查看数据包的数据部分。 在这个任务中,我们展示了如何使用隧道机制绕过这种出口过滤。 建立隧道有很多方法;在这项任务中,我们只关注SSH隧道。
Task 3.a: Telnet to Machine B through the firewall.
下面的命令在本地主机(端口8000)和机器B(使用默认端口22)之间建立SSH隧道;当数据包从B端出来时,它将被转发到机器C的端口23(telnet端口)。
1 | ssh -L 8000:192.168.164.128:23 seed@192.168.164.128 |
当我们将telnet传输到localhost的端口8000时,SSH将将我们所有的TCP数据包从localhost:8000上的隧道的一端传输到机器B上的隧道的另一端;从那里,数据包将被转发到机器B:23。
Task 3.b: Connect to Facebook using SSH Tunnel.
在这里,我们使用动态端口转发的方式,所以我们只指定了本地的端口,当B机器接收到我们本地机器发送过去的数据包后,根据数据包的信息动态确定转发到哪个端口上
1 | ssh -D 9000 seed@192.168.164.128 |
如下图,我们开启ssh
在Firefox里面我们用SOCKS
代理,将数据包发送到本地的9000端口,然后数据会通过我们的SSH隧道
如下图,我们成功绕过了过滤
Task 4: Evading Ingress Filtering
这里为了绕过INPUT形式的包过滤,我们采用了SSH反向代理的方式,首先我们在A机器上执行下命令,相当于将主动发起了连接,将机器192.168.164.131
的7000端口转发到了A机器的22端口
1 | ssh -p 22 -qngfNTR 7000:localhost:22 seed@192.168.164.131 |
然后我们在机器192.168.164.131
中执行下列命令,连接自己的7000端口,然后数据会通过隧道转发到A机器的22端口。
1 | ssh -p 7000 seed@localhost |
反向代理原理可用上图理解。