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 |


反向代理原理可用上图理解。
